diff --git a/.gitignore b/.gitignore index 24280a2ae..4f112771f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ typechain # Subgraph packages/subgraph/config/config.json -packages/subgraph/scripts/thegraph/api/config/* +packages/subgraph/scripts/thegraph/api/config/*.json packages/subgraph/subgraph.yaml packages/subgraph/generated packages/subgraph/abis/* diff --git a/packages/contracts/.openzeppelin/goerli.json b/packages/contracts/.openzeppelin/goerli.json index 3bceee1ec..43c2b4bab 100644 --- a/packages/contracts/.openzeppelin/goerli.json +++ b/packages/contracts/.openzeppelin/goerli.json @@ -2061,72 +2061,72 @@ "offset": 0, "slot": "1", "type": "t_bytes32", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:51" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:52" }, { "label": "markets", "offset": 0, "slot": "2", - "type": "t_mapping(t_uint256,t_struct(Marketplace)17674_storage)", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:53" + "type": "t_mapping(t_uint256,t_struct(Marketplace)18620_storage)", + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:54" }, { "label": "__uriToId", "offset": 0, "slot": "3", "type": "t_mapping(t_bytes32,t_uint256)", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:54" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:55" }, { "label": "marketCount", "offset": 0, "slot": "4", "type": "t_uint256", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:55" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:56" }, { "label": "_attestingSchemaId", "offset": 0, "slot": "5", "type": "t_bytes32", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:56" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:57" }, { "label": "borrowerAttestationSchemaId", "offset": 0, "slot": "6", "type": "t_bytes32", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:57" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:58" }, { "label": "version", "offset": 0, "slot": "7", "type": "t_uint256", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:59" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:60" }, { "label": "marketIsClosed", "offset": 0, "slot": "8", "type": "t_mapping(t_uint256,t_bool)", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:61" + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:62" }, { "label": "tellerAS", "offset": 0, "slot": "9", - "type": "t_contract(TellerAS)15136", - "contract": "MarketRegistry", - "src": "contracts/MarketRegistry.sol:63" + "type": "t_contract(TellerAS)13262", + "contract": "MarketRegistry_G1", + "src": "contracts/MarketRegistry_G1.sol:64" } ], "types": { @@ -2146,11 +2146,11 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_contract(TellerAS)15136": { + "t_contract(TellerAS)13262": { "label": "contract TellerAS", "numberOfBytes": "20" }, - "t_enum(PaymentCycleType)27275": { + "t_enum(PaymentCycleType)31799": { "label": "enum PaymentCycleType", "members": [ "Seconds", @@ -2158,7 +2158,7 @@ ], "numberOfBytes": "1" }, - "t_enum(PaymentType)27272": { + "t_enum(PaymentType)31796": { "label": "enum PaymentType", "members": [ "EMI", @@ -2178,28 +2178,28 @@ "label": "mapping(uint256 => bool)", "numberOfBytes": "32" }, - "t_mapping(t_uint256,t_struct(Marketplace)17674_storage)": { - "label": "mapping(uint256 => struct MarketRegistry.Marketplace)", + "t_mapping(t_uint256,t_struct(Marketplace)18620_storage)": { + "label": "mapping(uint256 => struct MarketRegistry_G1.Marketplace)", "numberOfBytes": "32" }, "t_string_storage": { "label": "string", "numberOfBytes": "32" }, - "t_struct(AddressSet)12722_storage": { + "t_struct(AddressSet)9958_storage": { "label": "struct EnumerableSet.AddressSet", "members": [ { "label": "_inner", - "type": "t_struct(Set)12407_storage", + "type": "t_struct(Set)9643_storage", "offset": 0, "slot": "0" } ], "numberOfBytes": "64" }, - "t_struct(Marketplace)17674_storage": { - "label": "struct MarketRegistry.Marketplace", + "t_struct(Marketplace)18620_storage": { + "label": "struct MarketRegistry_G1.Marketplace", "members": [ { "label": "owner", @@ -2227,7 +2227,7 @@ }, { "label": "verifiedLendersForMarket", - "type": "t_struct(AddressSet)12722_storage", + "type": "t_struct(AddressSet)9958_storage", "offset": 0, "slot": "3" }, @@ -2263,7 +2263,7 @@ }, { "label": "verifiedBorrowersForMarket", - "type": "t_struct(AddressSet)12722_storage", + "type": "t_struct(AddressSet)9958_storage", "offset": 0, "slot": "7" }, @@ -2281,20 +2281,20 @@ }, { "label": "paymentType", - "type": "t_enum(PaymentType)27272", + "type": "t_enum(PaymentType)31796", "offset": 20, "slot": "10" }, { "label": "paymentCycleType", - "type": "t_enum(PaymentCycleType)27275", + "type": "t_enum(PaymentCycleType)31799", "offset": 21, "slot": "10" } ], "numberOfBytes": "352" }, - "t_struct(Set)12407_storage": { + "t_struct(Set)9643_storage": { "label": "struct EnumerableSet.Set", "members": [ { @@ -2328,7 +2328,8 @@ "label": "uint8", "numberOfBytes": "1" } - } + }, + "namespaces": {} } }, "6fdd2b27004fef405d49a8e28cc74930069f1d173d713d490a960cdfa72ee239": { @@ -5750,6 +5751,999 @@ "types": {}, "namespaces": {} } + }, + "c18cf39362b57ac57034cf87b2d964387442f26a24387b8b8486d9019bd79d0f": { + "address": "0x196f007788011504e154319CF554e1BDb7928dbe", + "txHash": "0xac6416ad9f71d4aa291b2f6aa126170c687ee85b0cd7cc56c402c806952792c4", + "layout": { + "solcVersion": "0.8.9", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage", + "contract": "OwnableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94" + }, + { + "label": "_protocolFee", + "offset": 0, + "slot": "101", + "type": "t_uint16", + "contract": "ProtocolFee", + "src": "contracts/ProtocolFee.sol:8" + }, + { + "label": "_paused", + "offset": 2, + "slot": "101", + "type": "t_bool", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "PausableUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" + }, + { + "label": "nextBidId", + "offset": 0, + "slot": "151", + "type": "t_uint256", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:93" + }, + { + "label": "bids", + "offset": 0, + "slot": "152", + "type": "t_mapping(t_uint256,t_struct(Bid)26156_storage)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:96" + }, + { + "label": "borrowerBids", + "offset": 0, + "slot": "153", + "type": "t_mapping(t_address,t_array(t_uint256)dyn_storage)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:99" + }, + { + "label": "__lenderVolumeFilled", + "offset": 0, + "slot": "154", + "type": "t_mapping(t_address,t_uint256)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:102" + }, + { + "label": "__totalVolumeFilled", + "offset": 0, + "slot": "155", + "type": "t_uint256", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:105" + }, + { + "label": "__lendingTokensSet", + "offset": 0, + "slot": "156", + "type": "t_struct(AddressSet)9958_storage", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:108" + }, + { + "label": "marketRegistry", + "offset": 0, + "slot": "158", + "type": "t_contract(IMarketRegistry_V2)28416", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:110" + }, + { + "label": "reputationManager", + "offset": 0, + "slot": "159", + "type": "t_contract(IReputationManager)28478", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:111" + }, + { + "label": "_borrowerBidsActive", + "offset": 0, + "slot": "160", + "type": "t_mapping(t_address,t_struct(UintSet)10115_storage)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:114" + }, + { + "label": "bidDefaultDuration", + "offset": 0, + "slot": "161", + "type": "t_mapping(t_uint256,t_uint32)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:116" + }, + { + "label": "bidExpirationTime", + "offset": 0, + "slot": "162", + "type": "t_mapping(t_uint256,t_uint32)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:117" + }, + { + "label": "lenderVolumeFilled", + "offset": 0, + "slot": "163", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:121" + }, + { + "label": "totalVolumeFilled", + "offset": 0, + "slot": "164", + "type": "t_mapping(t_address,t_uint256)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:125" + }, + { + "label": "version", + "offset": 0, + "slot": "165", + "type": "t_uint256", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:127" + }, + { + "label": "uris", + "offset": 0, + "slot": "166", + "type": "t_mapping(t_uint256,t_string_storage)", + "contract": "TellerV2Storage_G0", + "src": "contracts/TellerV2Storage.sol:131" + }, + { + "label": "_trustedMarketForwarders", + "offset": 0, + "slot": "167", + "type": "t_mapping(t_uint256,t_address)", + "contract": "TellerV2Storage_G1", + "src": "contracts/TellerV2Storage.sol:136" + }, + { + "label": "_approvedForwarderSenders", + "offset": 0, + "slot": "168", + "type": "t_mapping(t_address,t_struct(AddressSet)9958_storage)", + "contract": "TellerV2Storage_G1", + "src": "contracts/TellerV2Storage.sol:138" + }, + { + "label": "lenderCommitmentForwarder", + "offset": 0, + "slot": "169", + "type": "t_address", + "contract": "TellerV2Storage_G2", + "src": "contracts/TellerV2Storage.sol:143" + }, + { + "label": "collateralManagerV1", + "offset": 0, + "slot": "170", + "type": "t_contract(ICollateralManagerV1)27504", + "contract": "TellerV2Storage_G3", + "src": "contracts/TellerV2Storage.sol:147" + }, + { + "label": "lenderManager", + "offset": 0, + "slot": "171", + "type": "t_contract(ILenderManager)28036", + "contract": "TellerV2Storage_G4", + "src": "contracts/TellerV2Storage.sol:152" + }, + { + "label": "bidPaymentCycleType", + "offset": 0, + "slot": "172", + "type": "t_mapping(t_uint256,t_enum(PaymentCycleType)31799)", + "contract": "TellerV2Storage_G4", + "src": "contracts/TellerV2Storage.sol:154" + }, + { + "label": "escrowVault", + "offset": 0, + "slot": "173", + "type": "t_contract(IEscrowVault)27868", + "contract": "TellerV2Storage_G5", + "src": "contracts/TellerV2Storage.sol:159" + }, + { + "label": "collateralManagerV2", + "offset": 0, + "slot": "174", + "type": "t_contract(ICollateralManagerV2)27537", + "contract": "TellerV2Storage_G6", + "src": "contracts/TellerV2Storage.sol:163" + }, + { + "label": "collateralManagerForBid", + "offset": 0, + "slot": "175", + "type": "t_mapping(t_uint256,t_address)", + "contract": "TellerV2Storage_G6", + "src": "contracts/TellerV2Storage.sol:164" + }, + { + "label": "bidMarketTermsId", + "offset": 0, + "slot": "176", + "type": "t_mapping(t_uint256,t_bytes32)", + "contract": "TellerV2Storage_G7", + "src": "contracts/TellerV2Storage.sol:170" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_array(t_uint256)dyn_storage": { + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_contract(ICollateralManagerV1)27504": { + "label": "contract ICollateralManagerV1", + "numberOfBytes": "20" + }, + "t_contract(ICollateralManagerV2)27537": { + "label": "contract ICollateralManagerV2", + "numberOfBytes": "20" + }, + "t_contract(IERC20)6032": { + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IEscrowVault)27868": { + "label": "contract IEscrowVault", + "numberOfBytes": "20" + }, + "t_contract(ILenderManager)28036": { + "label": "contract ILenderManager", + "numberOfBytes": "20" + }, + "t_contract(IMarketRegistry_V2)28416": { + "label": "contract IMarketRegistry_V2", + "numberOfBytes": "20" + }, + "t_contract(IReputationManager)28478": { + "label": "contract IReputationManager", + "numberOfBytes": "20" + }, + "t_enum(BidState)26128": { + "label": "enum BidState", + "members": [ + "NONEXISTENT", + "PENDING", + "CANCELLED", + "ACCEPTED", + "PAID", + "LIQUIDATED", + "CLOSED" + ], + "numberOfBytes": "1" + }, + "t_enum(PaymentCycleType)31799": { + "label": "enum PaymentCycleType", + "members": [ + "Seconds", + "Monthly" + ], + "numberOfBytes": "1" + }, + "t_enum(PaymentType)31796": { + "label": "enum PaymentType", + "members": [ + "EMI", + "Bullet" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_array(t_uint256)dyn_storage)": { + "label": "mapping(address => uint256[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(AddressSet)9958_storage)": { + "label": "mapping(address => struct EnumerableSet.AddressSet)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(UintSet)10115_storage)": { + "label": "mapping(address => struct EnumerableSet.UintSet)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_address)": { + "label": "mapping(uint256 => address)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_bytes32)": { + "label": "mapping(uint256 => bytes32)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_enum(PaymentCycleType)31799)": { + "label": "mapping(uint256 => enum PaymentCycleType)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_string_storage)": { + "label": "mapping(uint256 => string)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(Bid)26156_storage)": { + "label": "mapping(uint256 => struct Bid)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_uint32)": { + "label": "mapping(uint256 => uint32)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(AddressSet)9958_storage": { + "label": "struct EnumerableSet.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)9643_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Bid)26156_storage": { + "label": "struct Bid", + "members": [ + { + "label": "borrower", + "type": "t_address", + "offset": 0, + "slot": "0" + }, + { + "label": "receiver", + "type": "t_address", + "offset": 0, + "slot": "1" + }, + { + "label": "lender", + "type": "t_address", + "offset": 0, + "slot": "2" + }, + { + "label": "marketplaceId", + "type": "t_uint256", + "offset": 0, + "slot": "3" + }, + { + "label": "_metadataURI", + "type": "t_bytes32", + "offset": 0, + "slot": "4" + }, + { + "label": "loanDetails", + "type": "t_struct(LoanDetails)26173_storage", + "offset": 0, + "slot": "5" + }, + { + "label": "terms", + "type": "t_struct(Terms)26180_storage", + "offset": 0, + "slot": "10" + }, + { + "label": "state", + "type": "t_enum(BidState)26128", + "offset": 0, + "slot": "12" + }, + { + "label": "paymentType", + "type": "t_enum(PaymentType)31796", + "offset": 1, + "slot": "12" + } + ], + "numberOfBytes": "416" + }, + "t_struct(LoanDetails)26173_storage": { + "label": "struct LoanDetails", + "members": [ + { + "label": "lendingToken", + "type": "t_contract(IERC20)6032", + "offset": 0, + "slot": "0" + }, + { + "label": "principal", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "totalRepaid", + "type": "t_struct(Payment)26133_storage", + "offset": 0, + "slot": "2" + }, + { + "label": "timestamp", + "type": "t_uint32", + "offset": 0, + "slot": "4" + }, + { + "label": "acceptedTimestamp", + "type": "t_uint32", + "offset": 4, + "slot": "4" + }, + { + "label": "lastRepaidTimestamp", + "type": "t_uint32", + "offset": 8, + "slot": "4" + }, + { + "label": "loanDuration", + "type": "t_uint32", + "offset": 12, + "slot": "4" + } + ], + "numberOfBytes": "160" + }, + "t_struct(Payment)26133_storage": { + "label": "struct Payment", + "members": [ + { + "label": "principal", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "interest", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Set)9643_storage": { + "label": "struct EnumerableSet.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Terms)26180_storage": { + "label": "struct Terms", + "members": [ + { + "label": "paymentCycleAmount", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "paymentCycle", + "type": "t_uint32", + "offset": 0, + "slot": "1" + }, + { + "label": "APR", + "type": "t_uint16", + "offset": 4, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(UintSet)10115_storage": { + "label": "struct EnumerableSet.UintSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)9643_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": {} + } + }, + "20570c57e6662325ec4c9ebc918d7e4112ffb370b4854b74ffbe809c14746099": { + "address": "0xC66e1FdaB5a2BC7bADAEc38AbE607b0E3F28C908", + "txHash": "0xcc30ad8f241c4ffe239270e19d62878b9bd0d6f04714684a59bb113420a0efb9", + "layout": { + "solcVersion": "0.8.9", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts/proxy/utils/Initializable.sol:67" + }, + { + "label": "__lenderAttestationSchemaId", + "offset": 0, + "slot": "1", + "type": "t_bytes32", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:51" + }, + { + "label": "markets", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_uint256,t_struct(Marketplace)4125_storage)", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:53" + }, + { + "label": "__uriToId", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_bytes32,t_uint256)", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:54" + }, + { + "label": "marketCount", + "offset": 0, + "slot": "4", + "type": "t_uint256", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:55" + }, + { + "label": "_attestingSchemaId", + "offset": 0, + "slot": "5", + "type": "t_bytes32", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:56" + }, + { + "label": "borrowerAttestationSchemaId", + "offset": 0, + "slot": "6", + "type": "t_bytes32", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:57" + }, + { + "label": "version", + "offset": 0, + "slot": "7", + "type": "t_uint256", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:59" + }, + { + "label": "marketIsClosed", + "offset": 0, + "slot": "8", + "type": "t_mapping(t_uint256,t_bool)", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:61" + }, + { + "label": "__teller_as_gap", + "offset": 0, + "slot": "9", + "type": "t_array(t_uint256)7_storage", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:66" + }, + { + "label": "marketTerms", + "offset": 0, + "slot": "16", + "type": "t_mapping(t_bytes32,t_struct(MarketplaceTerms)6242_storage)", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:69" + }, + { + "label": "currentMarketTermsForMarket", + "offset": 0, + "slot": "17", + "type": "t_mapping(t_uint256,t_bytes32)", + "contract": "MarketRegistry_G2", + "src": "contracts/MarketRegistry_G2.sol:72" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)7_storage": { + "label": "uint256[7]", + "numberOfBytes": "224" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_enum(PaymentCycleType)8153": { + "label": "enum PaymentCycleType", + "members": [ + "Seconds", + "Monthly" + ], + "numberOfBytes": "1" + }, + "t_enum(PaymentType)8150": { + "label": "enum PaymentType", + "members": [ + "EMI", + "Bullet" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bytes32)": { + "label": "mapping(address => bytes32)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(MarketplaceTerms)6242_storage)": { + "label": "mapping(bytes32 => struct IMarketRegistry_V2.MarketplaceTerms)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_bool)": { + "label": "mapping(uint256 => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_bytes32)": { + "label": "mapping(uint256 => bytes32)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(Marketplace)4125_storage)": { + "label": "mapping(uint256 => struct MarketRegistry_G2.Marketplace)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(AddressSet)3770_storage": { + "label": "struct EnumerableSet.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)3455_storage", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Marketplace)4125_storage": { + "label": "struct MarketRegistry_G2.Marketplace", + "members": [ + { + "label": "owner", + "type": "t_address", + "offset": 0, + "slot": "0" + }, + { + "label": "metadataURI", + "type": "t_string_storage", + "offset": 0, + "slot": "1" + }, + { + "label": "marketplaceFeePercent", + "type": "t_uint16", + "offset": 0, + "slot": "2" + }, + { + "label": "lenderAttestationRequired", + "type": "t_bool", + "offset": 2, + "slot": "2" + }, + { + "label": "verifiedLendersForMarket", + "type": "t_struct(AddressSet)3770_storage", + "offset": 0, + "slot": "3" + }, + { + "label": "_lenderAttestationIds", + "type": "t_mapping(t_address,t_bytes32)", + "offset": 0, + "slot": "5" + }, + { + "label": "paymentCycleDuration", + "type": "t_uint32", + "offset": 0, + "slot": "6" + }, + { + "label": "paymentDefaultDuration", + "type": "t_uint32", + "offset": 4, + "slot": "6" + }, + { + "label": "bidExpirationTime", + "type": "t_uint32", + "offset": 8, + "slot": "6" + }, + { + "label": "borrowerAttestationRequired", + "type": "t_bool", + "offset": 12, + "slot": "6" + }, + { + "label": "verifiedBorrowersForMarket", + "type": "t_struct(AddressSet)3770_storage", + "offset": 0, + "slot": "7" + }, + { + "label": "_borrowerAttestationIds", + "type": "t_mapping(t_address,t_bytes32)", + "offset": 0, + "slot": "9" + }, + { + "label": "feeRecipient", + "type": "t_address", + "offset": 0, + "slot": "10" + }, + { + "label": "paymentType", + "type": "t_enum(PaymentType)8150", + "offset": 20, + "slot": "10" + }, + { + "label": "paymentCycleType", + "type": "t_enum(PaymentCycleType)8153", + "offset": 21, + "slot": "10" + } + ], + "numberOfBytes": "352" + }, + "t_struct(MarketplaceTerms)6242_storage": { + "label": "struct IMarketRegistry_V2.MarketplaceTerms", + "members": [ + { + "label": "marketplaceFeePercent", + "type": "t_uint16", + "offset": 0, + "slot": "0" + }, + { + "label": "paymentType", + "type": "t_enum(PaymentType)8150", + "offset": 2, + "slot": "0" + }, + { + "label": "paymentCycleType", + "type": "t_enum(PaymentCycleType)8153", + "offset": 3, + "slot": "0" + }, + { + "label": "paymentCycleDuration", + "type": "t_uint32", + "offset": 4, + "slot": "0" + }, + { + "label": "paymentDefaultDuration", + "type": "t_uint32", + "offset": 8, + "slot": "0" + }, + { + "label": "bidExpirationTime", + "type": "t_uint32", + "offset": 12, + "slot": "0" + }, + { + "label": "feeRecipient", + "type": "t_address", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Set)3455_storage": { + "label": "struct EnumerableSet.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": {} + } } } } diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G1.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G1.sol index e44f922b7..d555ee751 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G1.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G1.sol @@ -18,7 +18,7 @@ import "../../libraries/NumbersLib.sol"; import { IPool } from "../../interfaces/aave/IPool.sol"; import { IFlashLoanSimpleReceiver } from "../../interfaces/aave/IFlashLoanSimpleReceiver.sol"; import { IPoolAddressesProvider } from "../../interfaces/aave/IPoolAddressesProvider.sol"; - + //https://docs.aave.com/developers/v/1.0/tutorials/performing-a-flash-loan/...-in-your-project contract FlashRolloverLoan_G1 is IFlashLoanSimpleReceiver, IFlashRolloverLoan { @@ -205,6 +205,7 @@ If the new loan pays out (after fees) MORE than the aave loan amount+ fee) then ) internal returns (uint256 repayAmount_) { uint256 fundsBeforeRepayment = IERC20Upgradeable(_principalToken) .balanceOf(address(this)); + IERC20Upgradeable(_principalToken).approve( address(TELLER_V2), diff --git a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G2.sol b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G2.sol index 5a05ce443..e959a1d57 100644 --- a/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G2.sol +++ b/packages/contracts/contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G2.sol @@ -86,11 +86,9 @@ contract FlashRolloverLoan_G2 is FlashRolloverLoan_G1 { * @param _commitmentId The ID of the commitment for which to fetch the market ID. * @return The ID of the market associated with the provided commitment. */ - function _getMarketIdForCommitment(uint256 _commitmentId) - internal - view - returns (uint256) - { + function _getMarketIdForCommitment( + uint256 _commitmentId + ) internal view returns (uint256) { return LENDER_COMMITMENT_FORWARDER.getCommitmentMarketId(_commitmentId); } @@ -99,11 +97,9 @@ contract FlashRolloverLoan_G2 is FlashRolloverLoan_G1 { * @param _marketId The ID of the market for which to fetch the fee percentage. * @return The marketplace fee percentage for the provided market ID. */ - function _getMarketFeePct(uint256 _marketId) - internal - view - returns (uint16) - { + function _getMarketFeePct( + uint256 _marketId + ) internal view returns (uint16) { address _marketRegistryAddress = ITellerV2Storage(address(TELLER_V2)) .marketRegistry(); diff --git a/packages/contracts/contracts/MarketRegistry.sol b/packages/contracts/contracts/MarketRegistry.sol index bb5993894..2a30f6ac0 100644 --- a/packages/contracts/contracts/MarketRegistry.sol +++ b/packages/contracts/contracts/MarketRegistry.sol @@ -1,1260 +1,13 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -// Contracts -import "./EAS/TellerAS.sol"; -import "./EAS/TellerASResolver.sol"; +import "./MarketRegistry_G2.sol"; -//must continue to use this so storage slots are not broken -import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import "@openzeppelin/contracts/utils/Context.sol"; - -// Interfaces -import "./interfaces/IMarketRegistry.sol"; - -// Libraries -import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import { PaymentType } from "./libraries/V2Calculations.sol"; - -contract MarketRegistry is - IMarketRegistry, - Initializable, - Context, - TellerASResolver -{ - using EnumerableSet for EnumerableSet.AddressSet; - - /** Constant Variables **/ - - uint256 public constant CURRENT_CODE_VERSION = 8; - - /* Storage Variables */ - - struct Marketplace { - address owner; - string metadataURI; - uint16 marketplaceFeePercent; // 10000 is 100% - bool lenderAttestationRequired; - EnumerableSet.AddressSet verifiedLendersForMarket; - mapping(address => bytes32) lenderAttestationIds; - uint32 paymentCycleDuration; // unix time (seconds) - uint32 paymentDefaultDuration; //unix time - uint32 bidExpirationTime; //unix time - bool borrowerAttestationRequired; - EnumerableSet.AddressSet verifiedBorrowersForMarket; - mapping(address => bytes32) borrowerAttestationIds; - address feeRecipient; - PaymentType paymentType; - PaymentCycleType paymentCycleType; - } - - bytes32 public lenderAttestationSchemaId; - - mapping(uint256 => Marketplace) internal markets; - mapping(bytes32 => uint256) internal __uriToId; //DEPRECATED - uint256 public marketCount; - bytes32 private _attestingSchemaId; - bytes32 public borrowerAttestationSchemaId; - - uint256 public version; - - mapping(uint256 => bool) private marketIsClosed; - - TellerAS public tellerAS; - - /* Modifiers */ - - modifier ownsMarket(uint256 _marketId) { - require(_getMarketOwner(_marketId) == _msgSender(), "Not the owner"); - _; - } - - modifier withAttestingSchema(bytes32 schemaId) { - _attestingSchemaId = schemaId; - _; - _attestingSchemaId = bytes32(0); - } - - /* Events */ - - event MarketCreated(address indexed owner, uint256 marketId); - event SetMarketURI(uint256 marketId, string uri); - event SetPaymentCycleDuration(uint256 marketId, uint32 duration); // DEPRECATED - used for subgraph reference - event SetPaymentCycle( - uint256 marketId, - PaymentCycleType paymentCycleType, - uint32 value - ); - event SetPaymentDefaultDuration(uint256 marketId, uint32 duration); - event SetBidExpirationTime(uint256 marketId, uint32 duration); - event SetMarketFee(uint256 marketId, uint16 feePct); - event LenderAttestation(uint256 marketId, address lender); - event BorrowerAttestation(uint256 marketId, address borrower); - event LenderRevocation(uint256 marketId, address lender); - event BorrowerRevocation(uint256 marketId, address borrower); - event MarketClosed(uint256 marketId); - event LenderExitMarket(uint256 marketId, address lender); - event BorrowerExitMarket(uint256 marketId, address borrower); - event SetMarketOwner(uint256 marketId, address newOwner); - event SetMarketFeeRecipient(uint256 marketId, address newRecipient); - event SetMarketLenderAttestation(uint256 marketId, bool required); - event SetMarketBorrowerAttestation(uint256 marketId, bool required); - event SetMarketPaymentType(uint256 marketId, PaymentType paymentType); - - /* External Functions */ - - function initialize(TellerAS _tellerAS) external initializer { - tellerAS = _tellerAS; - - lenderAttestationSchemaId = tellerAS.getASRegistry().register( - "(uint256 marketId, address lenderAddress)", - this - ); - borrowerAttestationSchemaId = tellerAS.getASRegistry().register( - "(uint256 marketId, address borrowerAddress)", - this - ); - } - - /** - * @notice Creates a new market. - * @param _initialOwner Address who will initially own the market. - * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made. - * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment. - * @param _bidExpirationTime Length of time in seconds before pending bids expire. - * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. - * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. - * @param _paymentType The payment type for loans in the market. - * @param _uri URI string to get metadata details about the market. - * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly - * @return marketId_ The market ID of the newly created market. - */ - function createMarket( - address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _requireLenderAttestation, - bool _requireBorrowerAttestation, - PaymentType _paymentType, - PaymentCycleType _paymentCycleType, - string calldata _uri - ) external returns (uint256 marketId_) { - marketId_ = _createMarket( - _initialOwner, - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, - _requireLenderAttestation, - _requireBorrowerAttestation, - _paymentType, - _paymentCycleType, - _uri - ); - } - - /** - * @notice Creates a new market. - * @dev Uses the default EMI payment type. - * @param _initialOwner Address who will initially own the market. - * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made. - * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment. - * @param _bidExpirationTime Length of time in seconds before pending bids expire. - * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. - * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. - * @param _uri URI string to get metadata details about the market. - * @return marketId_ The market ID of the newly created market. - */ - function createMarket( - address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _requireLenderAttestation, - bool _requireBorrowerAttestation, - string calldata _uri - ) external returns (uint256 marketId_) { - marketId_ = _createMarket( - _initialOwner, - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, - _requireLenderAttestation, - _requireBorrowerAttestation, - PaymentType.EMI, - PaymentCycleType.Seconds, - _uri - ); - } - - /** - * @notice Creates a new market. - * @param _initialOwner Address who will initially own the market. - * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made. - * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment. - * @param _bidExpirationTime Length of time in seconds before pending bids expire. - * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. - * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. - * @param _paymentType The payment type for loans in the market. - * @param _uri URI string to get metadata details about the market. - * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly - * @return marketId_ The market ID of the newly created market. - */ - function _createMarket( - address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _requireLenderAttestation, - bool _requireBorrowerAttestation, - PaymentType _paymentType, - PaymentCycleType _paymentCycleType, - string calldata _uri - ) internal returns (uint256 marketId_) { - require(_initialOwner != address(0), "Invalid owner address"); - // Increment market ID counter - marketId_ = ++marketCount; - - // Set the market owner - markets[marketId_].owner = _initialOwner; - - // Initialize market settings - _setMarketSettings( - marketId_, - _paymentCycleDuration, - _paymentType, - _paymentCycleType, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, - _requireBorrowerAttestation, - _requireLenderAttestation, - _uri - ); - - emit MarketCreated(_initialOwner, marketId_); - } - - /** - * @notice Closes a market so new bids cannot be added. - * @param _marketId The market ID for the market to close. - */ - - function closeMarket(uint256 _marketId) public ownsMarket(_marketId) { - if (!marketIsClosed[_marketId]) { - marketIsClosed[_marketId] = true; - - emit MarketClosed(_marketId); - } - } - - /** - * @notice Returns the status of a market existing and not being closed. - * @param _marketId The market ID for the market to check. - */ - function isMarketOpen(uint256 _marketId) - public - view - override - returns (bool) - { - return - markets[_marketId].owner != address(0) && - !marketIsClosed[_marketId]; - } - - /** - * @notice Returns the status of a market being open or closed for new bids. Does not indicate whether or not a market exists. - * @param _marketId The market ID for the market to check. - */ - function isMarketClosed(uint256 _marketId) - public - view - override - returns (bool) - { - return marketIsClosed[_marketId]; - } - - /** - * @notice Adds a lender to a market. - * @dev See {_attestStakeholder}. - */ - function attestLender( - uint256 _marketId, - address _lenderAddress, - uint256 _expirationTime - ) external { - _attestStakeholder(_marketId, _lenderAddress, _expirationTime, true); - } - - /** - * @notice Adds a lender to a market via delegated attestation. - * @dev See {_attestStakeholderViaDelegation}. - */ - function attestLender( - uint256 _marketId, - address _lenderAddress, - uint256 _expirationTime, - uint8 _v, - bytes32 _r, - bytes32 _s - ) external { - _attestStakeholderViaDelegation( - _marketId, - _lenderAddress, - _expirationTime, - true, - _v, - _r, - _s - ); - } - - /** - * @notice Removes a lender from an market. - * @dev See {_revokeStakeholder}. - */ - function revokeLender(uint256 _marketId, address _lenderAddress) external { - _revokeStakeholder(_marketId, _lenderAddress, true); - } - - /** - * @notice Removes a borrower from a market via delegated revocation. - * @dev See {_revokeStakeholderViaDelegation}. - */ - function revokeLender( - uint256 _marketId, - address _lenderAddress, - uint8 _v, - bytes32 _r, - bytes32 _s - ) external { - _revokeStakeholderViaDelegation( - _marketId, - _lenderAddress, - true, - _v, - _r, - _s - ); - } - - /** - * @notice Allows a lender to voluntarily leave a market. - * @param _marketId The market ID to leave. - */ - function lenderExitMarket(uint256 _marketId) external { - // Remove lender address from market set - bool response = markets[_marketId].verifiedLendersForMarket.remove( - _msgSender() - ); - if (response) { - emit LenderExitMarket(_marketId, _msgSender()); - } - } - - /** - * @notice Adds a borrower to a market. - * @dev See {_attestStakeholder}. - */ - function attestBorrower( - uint256 _marketId, - address _borrowerAddress, - uint256 _expirationTime - ) external { - _attestStakeholder(_marketId, _borrowerAddress, _expirationTime, false); - } - - /** - * @notice Adds a borrower to a market via delegated attestation. - * @dev See {_attestStakeholderViaDelegation}. - */ - function attestBorrower( - uint256 _marketId, - address _borrowerAddress, - uint256 _expirationTime, - uint8 _v, - bytes32 _r, - bytes32 _s - ) external { - _attestStakeholderViaDelegation( - _marketId, - _borrowerAddress, - _expirationTime, - false, - _v, - _r, - _s - ); - } - - /** - * @notice Removes a borrower from an market. - * @dev See {_revokeStakeholder}. - */ - function revokeBorrower(uint256 _marketId, address _borrowerAddress) - external - { - _revokeStakeholder(_marketId, _borrowerAddress, false); - } - - /** - * @notice Removes a borrower from a market via delegated revocation. - * @dev See {_revokeStakeholderViaDelegation}. - */ - function revokeBorrower( - uint256 _marketId, - address _borrowerAddress, - uint8 _v, - bytes32 _r, - bytes32 _s - ) external { - _revokeStakeholderViaDelegation( - _marketId, - _borrowerAddress, - false, - _v, - _r, - _s - ); - } - - /** - * @notice Allows a borrower to voluntarily leave a market. - * @param _marketId The market ID to leave. - */ - function borrowerExitMarket(uint256 _marketId) external { - // Remove borrower address from market set - bool response = markets[_marketId].verifiedBorrowersForMarket.remove( - _msgSender() - ); - if (response) { - emit BorrowerExitMarket(_marketId, _msgSender()); - } - } - - /** - * @notice Verifies an attestation is valid. - * @dev This function must only be called by the `attestLender` function above. - * @param recipient Lender's address who is being attested. - * @param schema The schema used for the attestation. - * @param data Data the must include the market ID and lender's address - * @param - * @param attestor Market owner's address who signed the attestation. - * @return Boolean indicating the attestation was successful. - */ - function resolve( - address recipient, - bytes calldata schema, - bytes calldata data, - uint256 /* expirationTime */, - address attestor - ) external payable override returns (bool) { - bytes32 attestationSchemaId = keccak256( - abi.encodePacked(schema, address(this)) - ); - (uint256 marketId, address lenderAddress) = abi.decode( - data, - (uint256, address) - ); - return - (_attestingSchemaId == attestationSchemaId && - recipient == lenderAddress && - attestor == _getMarketOwner(marketId)) || - attestor == address(this); - } - - /** - * @notice Transfers ownership of a marketplace. - * @param _marketId The ID of a market. - * @param _newOwner Address of the new market owner. - * - * Requirements: - * - The caller must be the current owner. - */ - function transferMarketOwnership(uint256 _marketId, address _newOwner) - public - ownsMarket(_marketId) - { - markets[_marketId].owner = _newOwner; - emit SetMarketOwner(_marketId, _newOwner); - } - - /** - * @notice Updates multiple market settings for a given market. - * @param _marketId The ID of a market. - * @param _paymentCycleDuration Delinquency duration for new loans - * @param _newPaymentType The payment type for the market. - * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly - * @param _paymentDefaultDuration Default duration for new loans - * @param _bidExpirationTime Duration of time before a bid is considered out of date - * @param _metadataURI A URI that points to a market's metadata. - * - * Requirements: - * - The caller must be the current owner. - */ - function updateMarketSettings( - uint256 _marketId, - uint32 _paymentCycleDuration, - PaymentType _newPaymentType, - PaymentCycleType _paymentCycleType, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _borrowerAttestationRequired, - bool _lenderAttestationRequired, - string calldata _metadataURI - ) public ownsMarket(_marketId) { - _setMarketSettings( - _marketId, - _paymentCycleDuration, - _newPaymentType, - _paymentCycleType, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, - _borrowerAttestationRequired, - _lenderAttestationRequired, - _metadataURI - ); - } - - /** - * @notice Sets the fee recipient address for a market. - * @param _marketId The ID of a market. - * @param _recipient Address of the new fee recipient. - * - * Requirements: - * - The caller must be the current owner. - */ - function setMarketFeeRecipient(uint256 _marketId, address _recipient) - public - ownsMarket(_marketId) - { - markets[_marketId].feeRecipient = _recipient; - emit SetMarketFeeRecipient(_marketId, _recipient); - } - - /** - * @notice Sets the metadata URI for a market. - * @param _marketId The ID of a market. - * @param _uri A URI that points to a market's metadata. - * - * Requirements: - * - The caller must be the current owner. - */ - function setMarketURI(uint256 _marketId, string calldata _uri) - public - ownsMarket(_marketId) - { - //We do string comparison by checking the hashes of the strings against one another - if ( - keccak256(abi.encodePacked(_uri)) != - keccak256(abi.encodePacked(markets[_marketId].metadataURI)) - ) { - markets[_marketId].metadataURI = _uri; - - emit SetMarketURI(_marketId, _uri); - } - } - - /** - * @notice Sets the duration of new loans for this market before they turn delinquent. - * @notice Changing this value does not change the terms of existing loans for this market. - * @param _marketId The ID of a market. - * @param _paymentCycleType Cycle type (seconds or monthly) - * @param _duration Delinquency duration for new loans - */ - function setPaymentCycle( - uint256 _marketId, - PaymentCycleType _paymentCycleType, - uint32 _duration - ) public ownsMarket(_marketId) { - require( - (_paymentCycleType == PaymentCycleType.Seconds) || - (_paymentCycleType == PaymentCycleType.Monthly && - _duration == 0), - "monthly payment cycle duration cannot be set" - ); - Marketplace storage market = markets[_marketId]; - uint32 duration = _paymentCycleType == PaymentCycleType.Seconds - ? _duration - : 30 days; - if ( - _paymentCycleType != market.paymentCycleType || - duration != market.paymentCycleDuration - ) { - markets[_marketId].paymentCycleType = _paymentCycleType; - markets[_marketId].paymentCycleDuration = duration; - - emit SetPaymentCycle(_marketId, _paymentCycleType, duration); - } - } - - /** - * @notice Sets the duration of new loans for this market before they turn defaulted. - * @notice Changing this value does not change the terms of existing loans for this market. - * @param _marketId The ID of a market. - * @param _duration Default duration for new loans - */ - function setPaymentDefaultDuration(uint256 _marketId, uint32 _duration) - public - ownsMarket(_marketId) - { - if (_duration != markets[_marketId].paymentDefaultDuration) { - markets[_marketId].paymentDefaultDuration = _duration; - - emit SetPaymentDefaultDuration(_marketId, _duration); - } - } - - function setBidExpirationTime(uint256 _marketId, uint32 _duration) - public - ownsMarket(_marketId) +contract MarketRegistry is MarketRegistry_G2 { + /*constructor(address _tellerV2, address _marketRegistry) + MarketRegistry_G2(_tellerV2, _marketRegistry) { - if (_duration != markets[_marketId].bidExpirationTime) { - markets[_marketId].bidExpirationTime = _duration; - - emit SetBidExpirationTime(_marketId, _duration); - } - } - - /** - * @notice Sets the fee for the market. - * @param _marketId The ID of a market. - * @param _newPercent The percentage fee in basis points. - * - * Requirements: - * - The caller must be the current owner. - */ - function setMarketFeePercent(uint256 _marketId, uint16 _newPercent) - public - ownsMarket(_marketId) - { - require(_newPercent >= 0 && _newPercent <= 10000, "invalid percent"); - if (_newPercent != markets[_marketId].marketplaceFeePercent) { - markets[_marketId].marketplaceFeePercent = _newPercent; - emit SetMarketFee(_marketId, _newPercent); - } - } - - /** - * @notice Set the payment type for the market. - * @param _marketId The ID of the market. - * @param _newPaymentType The payment type for the market. - */ - function setMarketPaymentType( - uint256 _marketId, - PaymentType _newPaymentType - ) public ownsMarket(_marketId) { - if (_newPaymentType != markets[_marketId].paymentType) { - markets[_marketId].paymentType = _newPaymentType; - emit SetMarketPaymentType(_marketId, _newPaymentType); - } - } - - /** - * @notice Enable/disables market whitelist for lenders. - * @param _marketId The ID of a market. - * @param _required Boolean indicating if the market requires whitelist. - * - * Requirements: - * - The caller must be the current owner. - */ - function setLenderAttestationRequired(uint256 _marketId, bool _required) - public - ownsMarket(_marketId) - { - if (_required != markets[_marketId].lenderAttestationRequired) { - markets[_marketId].lenderAttestationRequired = _required; - emit SetMarketLenderAttestation(_marketId, _required); - } - } - - /** - * @notice Enable/disables market whitelist for borrowers. - * @param _marketId The ID of a market. - * @param _required Boolean indicating if the market requires whitelist. - * - * Requirements: - * - The caller must be the current owner. - */ - function setBorrowerAttestationRequired(uint256 _marketId, bool _required) - public - ownsMarket(_marketId) - { - if (_required != markets[_marketId].borrowerAttestationRequired) { - markets[_marketId].borrowerAttestationRequired = _required; - emit SetMarketBorrowerAttestation(_marketId, _required); - } - } - - /** - * @notice Gets the data associated with a market. - * @param _marketId The ID of a market. - */ - function getMarketData(uint256 _marketId) - public - view - returns ( - address owner, - uint32 paymentCycleDuration, - uint32 paymentDefaultDuration, - uint32 loanExpirationTime, - string memory metadataURI, - uint16 marketplaceFeePercent, - bool lenderAttestationRequired - ) - { - return ( - markets[_marketId].owner, - markets[_marketId].paymentCycleDuration, - markets[_marketId].paymentDefaultDuration, - markets[_marketId].bidExpirationTime, - markets[_marketId].metadataURI, - markets[_marketId].marketplaceFeePercent, - markets[_marketId].lenderAttestationRequired - ); - } - - /** - * @notice Gets the attestation requirements for a given market. - * @param _marketId The ID of the market. - */ - function getMarketAttestationRequirements(uint256 _marketId) - public - view - returns ( - bool lenderAttestationRequired, - bool borrowerAttestationRequired - ) - { - return ( - markets[_marketId].lenderAttestationRequired, - markets[_marketId].borrowerAttestationRequired - ); - } - - /** - * @notice Gets the address of a market's owner. - * @param _marketId The ID of a market. - * @return The address of a market's owner. - */ - function getMarketOwner(uint256 _marketId) - public - view - virtual - override - returns (address) - { - return _getMarketOwner(_marketId); - } - - /** - * @notice Gets the address of a market's owner. - * @param _marketId The ID of a market. - * @return The address of a market's owner. - */ - function _getMarketOwner(uint256 _marketId) - internal - view - virtual - returns (address) - { - return markets[_marketId].owner; - } - - /** - * @notice Gets the fee recipient of a market. - * @param _marketId The ID of a market. - * @return The address of a market's fee recipient. - */ - function getMarketFeeRecipient(uint256 _marketId) - public - view - override - returns (address) - { - address recipient = markets[_marketId].feeRecipient; - - if (recipient == address(0)) { - return _getMarketOwner(_marketId); - } - - return recipient; - } - - /** - * @notice Gets the metadata URI of a market. - * @param _marketId The ID of a market. - * @return URI of a market's metadata. - */ - function getMarketURI(uint256 _marketId) - public - view - override - returns (string memory) - { - return markets[_marketId].metadataURI; - } - - /** - * @notice Gets the loan delinquent duration of a market. - * @param _marketId The ID of a market. - * @return Duration of a loan until it is delinquent. - * @return The type of payment cycle for loans in the market. - */ - function getPaymentCycle(uint256 _marketId) - public - view - override - returns (uint32, PaymentCycleType) - { - return ( - markets[_marketId].paymentCycleDuration, - markets[_marketId].paymentCycleType - ); - } - - /** - * @notice Gets the loan default duration of a market. - * @param _marketId The ID of a market. - * @return Duration of a loan repayment interval until it is default. - */ - function getPaymentDefaultDuration(uint256 _marketId) - public - view - override - returns (uint32) - { - return markets[_marketId].paymentDefaultDuration; - } - - /** - * @notice Get the payment type of a market. - * @param _marketId the ID of the market. - * @return The type of payment for loans in the market. - */ - function getPaymentType(uint256 _marketId) - public - view - override - returns (PaymentType) - { - return markets[_marketId].paymentType; - } - - function getBidExpirationTime(uint256 marketId) - public - view - override - returns (uint32) - { - return markets[marketId].bidExpirationTime; - } - - /** - * @notice Gets the marketplace fee in basis points - * @param _marketId The ID of a market. - * @return fee in basis points - */ - function getMarketplaceFee(uint256 _marketId) - public - view - override - returns (uint16 fee) - { - return markets[_marketId].marketplaceFeePercent; - } - - /** - * @notice Checks if a lender has been attested and added to a market. - * @param _marketId The ID of a market. - * @param _lenderAddress Address to check. - * @return isVerified_ Boolean indicating if a lender has been added to a market. - * @return uuid_ Bytes32 representing the UUID of the lender. - */ - function isVerifiedLender(uint256 _marketId, address _lenderAddress) - public - view - override - returns (bool isVerified_, bytes32 uuid_) - { - return - _isVerified( - _lenderAddress, - markets[_marketId].lenderAttestationRequired, - markets[_marketId].lenderAttestationIds, - markets[_marketId].verifiedLendersForMarket - ); - } - - /** - * @notice Checks if a borrower has been attested and added to a market. - * @param _marketId The ID of a market. - * @param _borrowerAddress Address of the borrower to check. - * @return isVerified_ Boolean indicating if a borrower has been added to a market. - * @return uuid_ Bytes32 representing the UUID of the borrower. - */ - function isVerifiedBorrower(uint256 _marketId, address _borrowerAddress) - public - view - override - returns (bool isVerified_, bytes32 uuid_) - { - return - _isVerified( - _borrowerAddress, - markets[_marketId].borrowerAttestationRequired, - markets[_marketId].borrowerAttestationIds, - markets[_marketId].verifiedBorrowersForMarket - ); - } - - /** - * @notice Gets addresses of all attested lenders. - * @param _marketId The ID of a market. - * @param _page Page index to start from. - * @param _perPage Number of items in a page to return. - * @return Array of addresses that have been added to a market. - */ - function getAllVerifiedLendersForMarket( - uint256 _marketId, - uint256 _page, - uint256 _perPage - ) public view returns (address[] memory) { - EnumerableSet.AddressSet storage set = markets[_marketId] - .verifiedLendersForMarket; - - return _getStakeholdersForMarket(set, _page, _perPage); - } - - /** - * @notice Gets addresses of all attested borrowers. - * @param _marketId The ID of the market. - * @param _page Page index to start from. - * @param _perPage Number of items in a page to return. - * @return Array of addresses that have been added to a market. - */ - function getAllVerifiedBorrowersForMarket( - uint256 _marketId, - uint256 _page, - uint256 _perPage - ) public view returns (address[] memory) { - EnumerableSet.AddressSet storage set = markets[_marketId] - .verifiedBorrowersForMarket; - return _getStakeholdersForMarket(set, _page, _perPage); - } - - /** - * @notice Sets multiple market settings for a given market. - * @param _marketId The ID of a market. - * @param _paymentCycleDuration Delinquency duration for new loans - * @param _newPaymentType The payment type for the market. - * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly - * @param _paymentDefaultDuration Default duration for new loans - * @param _bidExpirationTime Duration of time before a bid is considered out of date - * @param _metadataURI A URI that points to a market's metadata. - */ - function _setMarketSettings( - uint256 _marketId, - uint32 _paymentCycleDuration, - PaymentType _newPaymentType, - PaymentCycleType _paymentCycleType, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _borrowerAttestationRequired, - bool _lenderAttestationRequired, - string calldata _metadataURI - ) internal { - setMarketURI(_marketId, _metadataURI); - setPaymentDefaultDuration(_marketId, _paymentDefaultDuration); - setBidExpirationTime(_marketId, _bidExpirationTime); - setMarketFeePercent(_marketId, _feePercent); - setLenderAttestationRequired(_marketId, _lenderAttestationRequired); - setBorrowerAttestationRequired(_marketId, _borrowerAttestationRequired); - setMarketPaymentType(_marketId, _newPaymentType); - setPaymentCycle(_marketId, _paymentCycleType, _paymentCycleDuration); - } - - /** - * @notice Gets addresses of all attested relevant stakeholders. - * @param _set The stored set of stakeholders to index from. - * @param _page Page index to start from. - * @param _perPage Number of items in a page to return. - * @return stakeholders_ Array of addresses that have been added to a market. - */ - function _getStakeholdersForMarket( - EnumerableSet.AddressSet storage _set, - uint256 _page, - uint256 _perPage - ) internal view returns (address[] memory stakeholders_) { - uint256 len = _set.length(); - - uint256 start = _page * _perPage; - if (start <= len) { - uint256 end = start + _perPage; - // Ensure we do not go out of bounds - if (end > len) { - end = len; - } - - stakeholders_ = new address[](end - start); - for (uint256 i = start; i < end; i++) { - stakeholders_[i] = _set.at(i); - } - } - } - - /* Internal Functions */ - - /** - * @notice Adds a stakeholder (lender or borrower) to a market. - * @param _marketId The market ID to add a borrower to. - * @param _stakeholderAddress The address of the stakeholder to add to the market. - * @param _expirationTime The expiration time of the attestation. - * @param _expirationTime The expiration time of the attestation. - * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. - */ - function _attestStakeholder( - uint256 _marketId, - address _stakeholderAddress, - uint256 _expirationTime, - bool _isLender - ) - internal - virtual - withAttestingSchema( - _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId - ) - { - require( - _msgSender() == _getMarketOwner(_marketId), - "Not the market owner" - ); - - // Submit attestation for borrower to join a market - bytes32 uuid = tellerAS.attest( - _stakeholderAddress, - _attestingSchemaId, // set by the modifier - _expirationTime, - 0, - abi.encode(_marketId, _stakeholderAddress) - ); - _attestStakeholderVerification( - _marketId, - _stakeholderAddress, - uuid, - _isLender - ); - } - - /** - * @notice Adds a stakeholder (lender or borrower) to a market via delegated attestation. - * @dev The signature must match that of the market owner. - * @param _marketId The market ID to add a lender to. - * @param _stakeholderAddress The address of the lender to add to the market. - * @param _expirationTime The expiration time of the attestation. - * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. - * @param _v Signature value - * @param _r Signature value - * @param _s Signature value - */ - function _attestStakeholderViaDelegation( - uint256 _marketId, - address _stakeholderAddress, - uint256 _expirationTime, - bool _isLender, - uint8 _v, - bytes32 _r, - bytes32 _s - ) - internal - virtual - withAttestingSchema( - _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId - ) - { - // NOTE: block scope to prevent stack too deep! - bytes32 uuid; - { - bytes memory data = abi.encode(_marketId, _stakeholderAddress); - address attestor = _getMarketOwner(_marketId); - // Submit attestation for stakeholder to join a market (attestation must be signed by market owner) - uuid = tellerAS.attestByDelegation( - _stakeholderAddress, - _attestingSchemaId, // set by the modifier - _expirationTime, - 0, - data, - attestor, - _v, - _r, - _s - ); - } - _attestStakeholderVerification( - _marketId, - _stakeholderAddress, - uuid, - _isLender - ); - } - - /** - * @notice Adds a stakeholder (borrower/lender) to a market. - * @param _marketId The market ID to add a stakeholder to. - * @param _stakeholderAddress The address of the stakeholder to add to the market. - * @param _uuid The UUID of the attestation created. - * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. - */ - function _attestStakeholderVerification( - uint256 _marketId, - address _stakeholderAddress, - bytes32 _uuid, - bool _isLender - ) internal virtual { - if (_isLender) { - // Store the lender attestation ID for the market ID - markets[_marketId].lenderAttestationIds[ - _stakeholderAddress - ] = _uuid; - // Add lender address to market set - markets[_marketId].verifiedLendersForMarket.add( - _stakeholderAddress - ); - - emit LenderAttestation(_marketId, _stakeholderAddress); - } else { - // Store the lender attestation ID for the market ID - markets[_marketId].borrowerAttestationIds[ - _stakeholderAddress - ] = _uuid; - // Add lender address to market set - markets[_marketId].verifiedBorrowersForMarket.add( - _stakeholderAddress - ); - - emit BorrowerAttestation(_marketId, _stakeholderAddress); - } - } - - /** - * @notice Removes a stakeholder from an market. - * @dev The caller must be the market owner. - * @param _marketId The market ID to remove the borrower from. - * @param _stakeholderAddress The address of the borrower to remove from the market. - * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. - */ - function _revokeStakeholder( - uint256 _marketId, - address _stakeholderAddress, - bool _isLender - ) internal virtual { - require( - _msgSender() == _getMarketOwner(_marketId), - "Not the market owner" - ); - - bytes32 uuid = _revokeStakeholderVerification( - _marketId, - _stakeholderAddress, - _isLender - ); - // NOTE: Disabling the call to revoke the attestation on EAS contracts - // tellerAS.revoke(uuid); - } - - /** - * @notice Removes a stakeholder from an market via delegated revocation. - * @param _marketId The market ID to remove the borrower from. - * @param _stakeholderAddress The address of the borrower to remove from the market. - * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. - * @param _v Signature value - * @param _r Signature value - * @param _s Signature value - */ - function _revokeStakeholderViaDelegation( - uint256 _marketId, - address _stakeholderAddress, - bool _isLender, - uint8 _v, - bytes32 _r, - bytes32 _s - ) internal { - bytes32 uuid = _revokeStakeholderVerification( - _marketId, - _stakeholderAddress, - _isLender - ); - // NOTE: Disabling the call to revoke the attestation on EAS contracts - // address attestor = markets[_marketId].owner; - // tellerAS.revokeByDelegation(uuid, attestor, _v, _r, _s); - } - - /** - * @notice Removes a stakeholder (borrower/lender) from a market. - * @param _marketId The market ID to remove the lender from. - * @param _stakeholderAddress The address of the stakeholder to remove from the market. - * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. - * @return uuid_ The ID of the previously verified attestation. - */ - function _revokeStakeholderVerification( - uint256 _marketId, - address _stakeholderAddress, - bool _isLender - ) internal virtual returns (bytes32 uuid_) { - if (_isLender) { - uuid_ = markets[_marketId].lenderAttestationIds[ - _stakeholderAddress - ]; - // Remove lender address from market set - markets[_marketId].verifiedLendersForMarket.remove( - _stakeholderAddress - ); - - emit LenderRevocation(_marketId, _stakeholderAddress); - } else { - uuid_ = markets[_marketId].borrowerAttestationIds[ - _stakeholderAddress - ]; - // Remove borrower address from market set - markets[_marketId].verifiedBorrowersForMarket.remove( - _stakeholderAddress - ); - - emit BorrowerRevocation(_marketId, _stakeholderAddress); - } - } - - /** - * @notice Checks if a stakeholder has been attested and added to a market. - * @param _stakeholderAddress Address of the stakeholder to check. - * @param _attestationRequired Stored boolean indicating if attestation is required for the stakeholder class. - * @param _stakeholderAttestationIds Mapping of attested Ids for the stakeholder class. - */ - function _isVerified( - address _stakeholderAddress, - bool _attestationRequired, - mapping(address => bytes32) storage _stakeholderAttestationIds, - EnumerableSet.AddressSet storage _verifiedStakeholderForMarket - ) internal view virtual returns (bool isVerified_, bytes32 uuid_) { - if (_attestationRequired) { - isVerified_ = - _verifiedStakeholderForMarket.contains(_stakeholderAddress) && - tellerAS.isAttestationActive( - _stakeholderAttestationIds[_stakeholderAddress] - ); - uuid_ = _stakeholderAttestationIds[_stakeholderAddress]; - } else { - isVerified_ = true; - } - } + // we only want this on an proxy deployment so it only affects the impl + //_disableInitializers(); + }*/ } diff --git a/packages/contracts/contracts/MarketRegistry_G1.sol b/packages/contracts/contracts/MarketRegistry_G1.sol new file mode 100644 index 000000000..546ecc85d --- /dev/null +++ b/packages/contracts/contracts/MarketRegistry_G1.sol @@ -0,0 +1,1261 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Contracts +import "./EAS/TellerAS.sol"; +import "./EAS/TellerASResolver.sol"; + +//must continue to use this so storage slots are not broken +import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; + +// Interfaces + +import "./interfaces/IMarketRegistry_V1.sol"; + +// Libraries +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import { PaymentType } from "./libraries/V2Calculations.sol"; + +contract MarketRegistry_G1 is + IMarketRegistry_V1, + Initializable, + Context, + TellerASResolver +{ + using EnumerableSet for EnumerableSet.AddressSet; + + /** Constant Variables **/ + + uint256 public constant CURRENT_CODE_VERSION = 8; + + /* Storage Variables */ + + struct Marketplace { + address owner; + string metadataURI; + uint16 marketplaceFeePercent; // 10000 is 100% + bool lenderAttestationRequired; + EnumerableSet.AddressSet verifiedLendersForMarket; + mapping(address => bytes32) lenderAttestationIds; + uint32 paymentCycleDuration; // unix time (seconds) + uint32 paymentDefaultDuration; //unix time + uint32 bidExpirationTime; //unix time + bool borrowerAttestationRequired; + EnumerableSet.AddressSet verifiedBorrowersForMarket; + mapping(address => bytes32) borrowerAttestationIds; + address feeRecipient; + PaymentType paymentType; + PaymentCycleType paymentCycleType; + } + + bytes32 public lenderAttestationSchemaId; + + mapping(uint256 => Marketplace) internal markets; + mapping(bytes32 => uint256) internal __uriToId; //DEPRECATED + uint256 public marketCount; + bytes32 private _attestingSchemaId; + bytes32 public borrowerAttestationSchemaId; + + uint256 public version; + + mapping(uint256 => bool) private marketIsClosed; + + TellerAS public tellerAS; + + /* Modifiers */ + + modifier ownsMarket(uint256 _marketId) { + require(_getMarketOwner(_marketId) == _msgSender(), "Not the owner"); + _; + } + + modifier withAttestingSchema(bytes32 schemaId) { + _attestingSchemaId = schemaId; + _; + _attestingSchemaId = bytes32(0); + } + + /* Events */ + + event MarketCreated(address indexed owner, uint256 marketId); + event SetMarketURI(uint256 marketId, string uri); + event SetPaymentCycleDuration(uint256 marketId, uint32 duration); // DEPRECATED - used for subgraph reference + event SetPaymentCycle( + uint256 marketId, + PaymentCycleType paymentCycleType, + uint32 value + ); + event SetPaymentDefaultDuration(uint256 marketId, uint32 duration); + event SetBidExpirationTime(uint256 marketId, uint32 duration); + event SetMarketFee(uint256 marketId, uint16 feePct); + event LenderAttestation(uint256 marketId, address lender); + event BorrowerAttestation(uint256 marketId, address borrower); + event LenderRevocation(uint256 marketId, address lender); + event BorrowerRevocation(uint256 marketId, address borrower); + event MarketClosed(uint256 marketId); + event LenderExitMarket(uint256 marketId, address lender); + event BorrowerExitMarket(uint256 marketId, address borrower); + event SetMarketOwner(uint256 marketId, address newOwner); + event SetMarketFeeRecipient(uint256 marketId, address newRecipient); + event SetMarketLenderAttestation(uint256 marketId, bool required); + event SetMarketBorrowerAttestation(uint256 marketId, bool required); + event SetMarketPaymentType(uint256 marketId, PaymentType paymentType); + + /* External Functions */ + + function initialize(TellerAS _tellerAS) external initializer { + tellerAS = _tellerAS; + + lenderAttestationSchemaId = tellerAS.getASRegistry().register( + "(uint256 marketId, address lenderAddress)", + this + ); + borrowerAttestationSchemaId = tellerAS.getASRegistry().register( + "(uint256 marketId, address borrowerAddress)", + this + ); + } + + /** + * @notice Creates a new market. + * @param _initialOwner Address who will initially own the market. + * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made. + * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment. + * @param _bidExpirationTime Length of time in seconds before pending bids expire. + * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. + * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. + * @param _paymentType The payment type for loans in the market. + * @param _uri URI string to get metadata details about the market. + * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly + * @return marketId_ The market ID of the newly created market. + */ + function createMarket( + address _initialOwner, + uint32 _paymentCycleDuration, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + PaymentType _paymentType, + PaymentCycleType _paymentCycleType, + string calldata _uri + ) external returns (uint256 marketId_) { + marketId_ = _createMarket( + _initialOwner, + _paymentCycleDuration, + _paymentDefaultDuration, + _bidExpirationTime, + _feePercent, + _requireLenderAttestation, + _requireBorrowerAttestation, + _paymentType, + _paymentCycleType, + _uri + ); + } + + /** + * @notice Creates a new market. + * @dev Uses the default EMI payment type. + * @param _initialOwner Address who will initially own the market. + * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made. + * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment. + * @param _bidExpirationTime Length of time in seconds before pending bids expire. + * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. + * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. + * @param _uri URI string to get metadata details about the market. + * @return marketId_ The market ID of the newly created market. + */ + function createMarket( + address _initialOwner, + uint32 _paymentCycleDuration, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + string calldata _uri + ) external returns (uint256 marketId_) { + marketId_ = _createMarket( + _initialOwner, + _paymentCycleDuration, + _paymentDefaultDuration, + _bidExpirationTime, + _feePercent, + _requireLenderAttestation, + _requireBorrowerAttestation, + PaymentType.EMI, + PaymentCycleType.Seconds, + _uri + ); + } + + /** + * @notice Creates a new market. + * @param _initialOwner Address who will initially own the market. + * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made. + * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment. + * @param _bidExpirationTime Length of time in seconds before pending bids expire. + * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. + * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. + * @param _paymentType The payment type for loans in the market. + * @param _uri URI string to get metadata details about the market. + * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly + * @return marketId_ The market ID of the newly created market. + */ + function _createMarket( + address _initialOwner, + uint32 _paymentCycleDuration, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + PaymentType _paymentType, + PaymentCycleType _paymentCycleType, + string calldata _uri + ) internal returns (uint256 marketId_) { + require(_initialOwner != address(0), "Invalid owner address"); + // Increment market ID counter + marketId_ = ++marketCount; + + // Set the market owner + markets[marketId_].owner = _initialOwner; + + // Initialize market settings + _setMarketSettings( + marketId_, + _paymentCycleDuration, + _paymentType, + _paymentCycleType, + _paymentDefaultDuration, + _bidExpirationTime, + _feePercent, + _requireBorrowerAttestation, + _requireLenderAttestation, + _uri + ); + + emit MarketCreated(_initialOwner, marketId_); + } + + /** + * @notice Closes a market so new bids cannot be added. + * @param _marketId The market ID for the market to close. + */ + + function closeMarket(uint256 _marketId) public ownsMarket(_marketId) { + if (!marketIsClosed[_marketId]) { + marketIsClosed[_marketId] = true; + + emit MarketClosed(_marketId); + } + } + + /** + * @notice Returns the status of a market existing and not being closed. + * @param _marketId The market ID for the market to check. + */ + function isMarketOpen(uint256 _marketId) + public + view + override + returns (bool) + { + return + markets[_marketId].owner != address(0) && + !marketIsClosed[_marketId]; + } + + /** + * @notice Returns the status of a market being open or closed for new bids. Does not indicate whether or not a market exists. + * @param _marketId The market ID for the market to check. + */ + function isMarketClosed(uint256 _marketId) + public + view + override + returns (bool) + { + return marketIsClosed[_marketId]; + } + + /** + * @notice Adds a lender to a market. + * @dev See {_attestStakeholder}. + */ + function attestLender( + uint256 _marketId, + address _lenderAddress, + uint256 _expirationTime + ) external { + _attestStakeholder(_marketId, _lenderAddress, _expirationTime, true); + } + + /** + * @notice Adds a lender to a market via delegated attestation. + * @dev See {_attestStakeholderViaDelegation}. + */ + function attestLender( + uint256 _marketId, + address _lenderAddress, + uint256 _expirationTime, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external { + _attestStakeholderViaDelegation( + _marketId, + _lenderAddress, + _expirationTime, + true, + _v, + _r, + _s + ); + } + + /** + * @notice Removes a lender from an market. + * @dev See {_revokeStakeholder}. + */ + function revokeLender(uint256 _marketId, address _lenderAddress) external { + _revokeStakeholder(_marketId, _lenderAddress, true); + } + + /** + * @notice Removes a borrower from a market via delegated revocation. + * @dev See {_revokeStakeholderViaDelegation}. + */ + function revokeLender( + uint256 _marketId, + address _lenderAddress, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external { + _revokeStakeholderViaDelegation( + _marketId, + _lenderAddress, + true, + _v, + _r, + _s + ); + } + + /** + * @notice Allows a lender to voluntarily leave a market. + * @param _marketId The market ID to leave. + */ + function lenderExitMarket(uint256 _marketId) external { + // Remove lender address from market set + bool response = markets[_marketId].verifiedLendersForMarket.remove( + _msgSender() + ); + if (response) { + emit LenderExitMarket(_marketId, _msgSender()); + } + } + + /** + * @notice Adds a borrower to a market. + * @dev See {_attestStakeholder}. + */ + function attestBorrower( + uint256 _marketId, + address _borrowerAddress, + uint256 _expirationTime + ) external { + _attestStakeholder(_marketId, _borrowerAddress, _expirationTime, false); + } + + /** + * @notice Adds a borrower to a market via delegated attestation. + * @dev See {_attestStakeholderViaDelegation}. + */ + function attestBorrower( + uint256 _marketId, + address _borrowerAddress, + uint256 _expirationTime, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external { + _attestStakeholderViaDelegation( + _marketId, + _borrowerAddress, + _expirationTime, + false, + _v, + _r, + _s + ); + } + + /** + * @notice Removes a borrower from an market. + * @dev See {_revokeStakeholder}. + */ + function revokeBorrower(uint256 _marketId, address _borrowerAddress) + external + { + _revokeStakeholder(_marketId, _borrowerAddress, false); + } + + /** + * @notice Removes a borrower from a market via delegated revocation. + * @dev See {_revokeStakeholderViaDelegation}. + */ + function revokeBorrower( + uint256 _marketId, + address _borrowerAddress, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external { + _revokeStakeholderViaDelegation( + _marketId, + _borrowerAddress, + false, + _v, + _r, + _s + ); + } + + /** + * @notice Allows a borrower to voluntarily leave a market. + * @param _marketId The market ID to leave. + */ + function borrowerExitMarket(uint256 _marketId) external { + // Remove borrower address from market set + bool response = markets[_marketId].verifiedBorrowersForMarket.remove( + _msgSender() + ); + if (response) { + emit BorrowerExitMarket(_marketId, _msgSender()); + } + } + + /** + * @notice Verifies an attestation is valid. + * @dev This function must only be called by the `attestLender` function above. + * @param recipient Lender's address who is being attested. + * @param schema The schema used for the attestation. + * @param data Data the must include the market ID and lender's address + * @param + * @param attestor Market owner's address who signed the attestation. + * @return Boolean indicating the attestation was successful. + */ + function resolve( + address recipient, + bytes calldata schema, + bytes calldata data, + uint256 /* expirationTime */, + address attestor + ) external payable override returns (bool) { + bytes32 attestationSchemaId = keccak256( + abi.encodePacked(schema, address(this)) + ); + (uint256 marketId, address lenderAddress) = abi.decode( + data, + (uint256, address) + ); + return + (_attestingSchemaId == attestationSchemaId && + recipient == lenderAddress && + attestor == _getMarketOwner(marketId)) || + attestor == address(this); + } + + /** + * @notice Transfers ownership of a marketplace. + * @param _marketId The ID of a market. + * @param _newOwner Address of the new market owner. + * + * Requirements: + * - The caller must be the current owner. + */ + function transferMarketOwnership(uint256 _marketId, address _newOwner) + public + ownsMarket(_marketId) + { + markets[_marketId].owner = _newOwner; + emit SetMarketOwner(_marketId, _newOwner); + } + + /** + * @notice Updates multiple market settings for a given market. + * @param _marketId The ID of a market. + * @param _paymentCycleDuration Delinquency duration for new loans + * @param _newPaymentType The payment type for the market. + * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly + * @param _paymentDefaultDuration Default duration for new loans + * @param _bidExpirationTime Duration of time before a bid is considered out of date + * @param _metadataURI A URI that points to a market's metadata. + * + * Requirements: + * - The caller must be the current owner. + */ + function updateMarketSettings( + uint256 _marketId, + uint32 _paymentCycleDuration, + PaymentType _newPaymentType, + PaymentCycleType _paymentCycleType, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _borrowerAttestationRequired, + bool _lenderAttestationRequired, + string calldata _metadataURI + ) public ownsMarket(_marketId) { + _setMarketSettings( + _marketId, + _paymentCycleDuration, + _newPaymentType, + _paymentCycleType, + _paymentDefaultDuration, + _bidExpirationTime, + _feePercent, + _borrowerAttestationRequired, + _lenderAttestationRequired, + _metadataURI + ); + } + + /** + * @notice Sets the fee recipient address for a market. + * @param _marketId The ID of a market. + * @param _recipient Address of the new fee recipient. + * + * Requirements: + * - The caller must be the current owner. + */ + function setMarketFeeRecipient(uint256 _marketId, address _recipient) + public + ownsMarket(_marketId) + { + markets[_marketId].feeRecipient = _recipient; + emit SetMarketFeeRecipient(_marketId, _recipient); + } + + /** + * @notice Sets the metadata URI for a market. + * @param _marketId The ID of a market. + * @param _uri A URI that points to a market's metadata. + * + * Requirements: + * - The caller must be the current owner. + */ + function setMarketURI(uint256 _marketId, string calldata _uri) + public + ownsMarket(_marketId) + { + //We do string comparison by checking the hashes of the strings against one another + if ( + keccak256(abi.encodePacked(_uri)) != + keccak256(abi.encodePacked(markets[_marketId].metadataURI)) + ) { + markets[_marketId].metadataURI = _uri; + + emit SetMarketURI(_marketId, _uri); + } + } + + /** + * @notice Sets the duration of new loans for this market before they turn delinquent. + * @notice Changing this value does not change the terms of existing loans for this market. + * @param _marketId The ID of a market. + * @param _paymentCycleType Cycle type (seconds or monthly) + * @param _duration Delinquency duration for new loans + */ + function setPaymentCycle( + uint256 _marketId, + PaymentCycleType _paymentCycleType, + uint32 _duration + ) public ownsMarket(_marketId) { + require( + (_paymentCycleType == PaymentCycleType.Seconds) || + (_paymentCycleType == PaymentCycleType.Monthly && + _duration == 0), + "monthly payment cycle duration cannot be set" + ); + Marketplace storage market = markets[_marketId]; + uint32 duration = _paymentCycleType == PaymentCycleType.Seconds + ? _duration + : 30 days; + if ( + _paymentCycleType != market.paymentCycleType || + duration != market.paymentCycleDuration + ) { + markets[_marketId].paymentCycleType = _paymentCycleType; + markets[_marketId].paymentCycleDuration = duration; + + emit SetPaymentCycle(_marketId, _paymentCycleType, duration); + } + } + + /** + * @notice Sets the duration of new loans for this market before they turn defaulted. + * @notice Changing this value does not change the terms of existing loans for this market. + * @param _marketId The ID of a market. + * @param _duration Default duration for new loans + */ + function setPaymentDefaultDuration(uint256 _marketId, uint32 _duration) + public + ownsMarket(_marketId) + { + if (_duration != markets[_marketId].paymentDefaultDuration) { + markets[_marketId].paymentDefaultDuration = _duration; + + emit SetPaymentDefaultDuration(_marketId, _duration); + } + } + + function setBidExpirationTime(uint256 _marketId, uint32 _duration) + public + ownsMarket(_marketId) + { + if (_duration != markets[_marketId].bidExpirationTime) { + markets[_marketId].bidExpirationTime = _duration; + + emit SetBidExpirationTime(_marketId, _duration); + } + } + + /** + * @notice Sets the fee for the market. + * @param _marketId The ID of a market. + * @param _newPercent The percentage fee in basis points. + * + * Requirements: + * - The caller must be the current owner. + */ + function setMarketFeePercent(uint256 _marketId, uint16 _newPercent) + public + ownsMarket(_marketId) + { + require(_newPercent >= 0 && _newPercent <= 10000, "invalid percent"); + if (_newPercent != markets[_marketId].marketplaceFeePercent) { + markets[_marketId].marketplaceFeePercent = _newPercent; + emit SetMarketFee(_marketId, _newPercent); + } + } + + /** + * @notice Set the payment type for the market. + * @param _marketId The ID of the market. + * @param _newPaymentType The payment type for the market. + */ + function setMarketPaymentType( + uint256 _marketId, + PaymentType _newPaymentType + ) public ownsMarket(_marketId) { + if (_newPaymentType != markets[_marketId].paymentType) { + markets[_marketId].paymentType = _newPaymentType; + emit SetMarketPaymentType(_marketId, _newPaymentType); + } + } + + /** + * @notice Enable/disables market whitelist for lenders. + * @param _marketId The ID of a market. + * @param _required Boolean indicating if the market requires whitelist. + * + * Requirements: + * - The caller must be the current owner. + */ + function setLenderAttestationRequired(uint256 _marketId, bool _required) + public + ownsMarket(_marketId) + { + if (_required != markets[_marketId].lenderAttestationRequired) { + markets[_marketId].lenderAttestationRequired = _required; + emit SetMarketLenderAttestation(_marketId, _required); + } + } + + /** + * @notice Enable/disables market whitelist for borrowers. + * @param _marketId The ID of a market. + * @param _required Boolean indicating if the market requires whitelist. + * + * Requirements: + * - The caller must be the current owner. + */ + function setBorrowerAttestationRequired(uint256 _marketId, bool _required) + public + ownsMarket(_marketId) + { + if (_required != markets[_marketId].borrowerAttestationRequired) { + markets[_marketId].borrowerAttestationRequired = _required; + emit SetMarketBorrowerAttestation(_marketId, _required); + } + } + + /** + * @notice Gets the data associated with a market. + * @param _marketId The ID of a market. + */ + function getMarketData(uint256 _marketId) + public + view + returns ( + address owner, + uint32 paymentCycleDuration, + uint32 paymentDefaultDuration, + uint32 loanExpirationTime, + string memory metadataURI, + uint16 marketplaceFeePercent, + bool lenderAttestationRequired + ) + { + return ( + markets[_marketId].owner, + markets[_marketId].paymentCycleDuration, + markets[_marketId].paymentDefaultDuration, + markets[_marketId].bidExpirationTime, + markets[_marketId].metadataURI, + markets[_marketId].marketplaceFeePercent, + markets[_marketId].lenderAttestationRequired + ); + } + + /** + * @notice Gets the attestation requirements for a given market. + * @param _marketId The ID of the market. + */ + function getMarketAttestationRequirements(uint256 _marketId) + public + view + returns ( + bool lenderAttestationRequired, + bool borrowerAttestationRequired + ) + { + return ( + markets[_marketId].lenderAttestationRequired, + markets[_marketId].borrowerAttestationRequired + ); + } + + /** + * @notice Gets the address of a market's owner. + * @param _marketId The ID of a market. + * @return The address of a market's owner. + */ + function getMarketOwner(uint256 _marketId) + public + view + virtual + override + returns (address) + { + return _getMarketOwner(_marketId); + } + + /** + * @notice Gets the address of a market's owner. + * @param _marketId The ID of a market. + * @return The address of a market's owner. + */ + function _getMarketOwner(uint256 _marketId) + internal + view + virtual + returns (address) + { + return markets[_marketId].owner; + } + + /** + * @notice Gets the fee recipient of a market. + * @param _marketId The ID of a market. + * @return The address of a market's fee recipient. + */ + function getMarketFeeRecipient(uint256 _marketId) + public + view + override + returns (address) + { + address recipient = markets[_marketId].feeRecipient; + + if (recipient == address(0)) { + return _getMarketOwner(_marketId); + } + + return recipient; + } + + /** + * @notice Gets the metadata URI of a market. + * @param _marketId The ID of a market. + * @return URI of a market's metadata. + */ + function getMarketURI(uint256 _marketId) + public + view + override + returns (string memory) + { + return markets[_marketId].metadataURI; + } + + /** + * @notice Gets the loan delinquent duration of a market. + * @param _marketId The ID of a market. + * @return Duration of a loan until it is delinquent. + * @return The type of payment cycle for loans in the market. + */ + function getPaymentCycle(uint256 _marketId) + public + view + override + returns (uint32, PaymentCycleType) + { + return ( + markets[_marketId].paymentCycleDuration, + markets[_marketId].paymentCycleType + ); + } + + /** + * @notice Gets the loan default duration of a market. + * @param _marketId The ID of a market. + * @return Duration of a loan repayment interval until it is default. + */ + function getPaymentDefaultDuration(uint256 _marketId) + public + view + override + returns (uint32) + { + return markets[_marketId].paymentDefaultDuration; + } + + /** + * @notice Get the payment type of a market. + * @param _marketId the ID of the market. + * @return The type of payment for loans in the market. + */ + function getPaymentType(uint256 _marketId) + public + view + override + returns (PaymentType) + { + return markets[_marketId].paymentType; + } + + function getBidExpirationTime(uint256 marketId) + public + view + override + returns (uint32) + { + return markets[marketId].bidExpirationTime; + } + + /** + * @notice Gets the marketplace fee in basis points + * @param _marketId The ID of a market. + * @return fee in basis points + */ + function getMarketplaceFee(uint256 _marketId) + public + view + override + returns (uint16 fee) + { + return markets[_marketId].marketplaceFeePercent; + } + + /** + * @notice Checks if a lender has been attested and added to a market. + * @param _marketId The ID of a market. + * @param _lenderAddress Address to check. + * @return isVerified_ Boolean indicating if a lender has been added to a market. + * @return uuid_ Bytes32 representing the UUID of the lender. + */ + function isVerifiedLender(uint256 _marketId, address _lenderAddress) + public + view + override + returns (bool isVerified_, bytes32 uuid_) + { + return + _isVerified( + _lenderAddress, + markets[_marketId].lenderAttestationRequired, + markets[_marketId].lenderAttestationIds, + markets[_marketId].verifiedLendersForMarket + ); + } + + /** + * @notice Checks if a borrower has been attested and added to a market. + * @param _marketId The ID of a market. + * @param _borrowerAddress Address of the borrower to check. + * @return isVerified_ Boolean indicating if a borrower has been added to a market. + * @return uuid_ Bytes32 representing the UUID of the borrower. + */ + function isVerifiedBorrower(uint256 _marketId, address _borrowerAddress) + public + view + override + returns (bool isVerified_, bytes32 uuid_) + { + return + _isVerified( + _borrowerAddress, + markets[_marketId].borrowerAttestationRequired, + markets[_marketId].borrowerAttestationIds, + markets[_marketId].verifiedBorrowersForMarket + ); + } + + /** + * @notice Gets addresses of all attested lenders. + * @param _marketId The ID of a market. + * @param _page Page index to start from. + * @param _perPage Number of items in a page to return. + * @return Array of addresses that have been added to a market. + */ + function getAllVerifiedLendersForMarket( + uint256 _marketId, + uint256 _page, + uint256 _perPage + ) public view returns (address[] memory) { + EnumerableSet.AddressSet storage set = markets[_marketId] + .verifiedLendersForMarket; + + return _getStakeholdersForMarket(set, _page, _perPage); + } + + /** + * @notice Gets addresses of all attested borrowers. + * @param _marketId The ID of the market. + * @param _page Page index to start from. + * @param _perPage Number of items in a page to return. + * @return Array of addresses that have been added to a market. + */ + function getAllVerifiedBorrowersForMarket( + uint256 _marketId, + uint256 _page, + uint256 _perPage + ) public view returns (address[] memory) { + EnumerableSet.AddressSet storage set = markets[_marketId] + .verifiedBorrowersForMarket; + return _getStakeholdersForMarket(set, _page, _perPage); + } + + /** + * @notice Sets multiple market settings for a given market. + * @param _marketId The ID of a market. + * @param _paymentCycleDuration Delinquency duration for new loans + * @param _newPaymentType The payment type for the market. + * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly + * @param _paymentDefaultDuration Default duration for new loans + * @param _bidExpirationTime Duration of time before a bid is considered out of date + * @param _metadataURI A URI that points to a market's metadata. + */ + function _setMarketSettings( + uint256 _marketId, + uint32 _paymentCycleDuration, + PaymentType _newPaymentType, + PaymentCycleType _paymentCycleType, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _borrowerAttestationRequired, + bool _lenderAttestationRequired, + string calldata _metadataURI + ) internal { + setMarketURI(_marketId, _metadataURI); + setPaymentDefaultDuration(_marketId, _paymentDefaultDuration); + setBidExpirationTime(_marketId, _bidExpirationTime); + setMarketFeePercent(_marketId, _feePercent); + setLenderAttestationRequired(_marketId, _lenderAttestationRequired); + setBorrowerAttestationRequired(_marketId, _borrowerAttestationRequired); + setMarketPaymentType(_marketId, _newPaymentType); + setPaymentCycle(_marketId, _paymentCycleType, _paymentCycleDuration); + } + + /** + * @notice Gets addresses of all attested relevant stakeholders. + * @param _set The stored set of stakeholders to index from. + * @param _page Page index to start from. + * @param _perPage Number of items in a page to return. + * @return stakeholders_ Array of addresses that have been added to a market. + */ + function _getStakeholdersForMarket( + EnumerableSet.AddressSet storage _set, + uint256 _page, + uint256 _perPage + ) internal view returns (address[] memory stakeholders_) { + uint256 len = _set.length(); + + uint256 start = _page * _perPage; + if (start <= len) { + uint256 end = start + _perPage; + // Ensure we do not go out of bounds + if (end > len) { + end = len; + } + + stakeholders_ = new address[](end - start); + for (uint256 i = start; i < end; i++) { + stakeholders_[i] = _set.at(i); + } + } + } + + /* Internal Functions */ + + /** + * @notice Adds a stakeholder (lender or borrower) to a market. + * @param _marketId The market ID to add a borrower to. + * @param _stakeholderAddress The address of the stakeholder to add to the market. + * @param _expirationTime The expiration time of the attestation. + * @param _expirationTime The expiration time of the attestation. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _attestStakeholder( + uint256 _marketId, + address _stakeholderAddress, + uint256 _expirationTime, + bool _isLender + ) + internal + virtual + withAttestingSchema( + _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId + ) + { + require( + _msgSender() == _getMarketOwner(_marketId), + "Not the market owner" + ); + + // Submit attestation for borrower to join a market + bytes32 uuid = tellerAS.attest( + _stakeholderAddress, + _attestingSchemaId, // set by the modifier + _expirationTime, + 0, + abi.encode(_marketId, _stakeholderAddress) + ); + _attestStakeholderVerification( + _marketId, + _stakeholderAddress, + uuid, + _isLender + ); + } + + /** + * @notice Adds a stakeholder (lender or borrower) to a market via delegated attestation. + * @dev The signature must match that of the market owner. + * @param _marketId The market ID to add a lender to. + * @param _stakeholderAddress The address of the lender to add to the market. + * @param _expirationTime The expiration time of the attestation. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + * @param _v Signature value + * @param _r Signature value + * @param _s Signature value + */ + function _attestStakeholderViaDelegation( + uint256 _marketId, + address _stakeholderAddress, + uint256 _expirationTime, + bool _isLender, + uint8 _v, + bytes32 _r, + bytes32 _s + ) + internal + virtual + withAttestingSchema( + _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId + ) + { + // NOTE: block scope to prevent stack too deep! + bytes32 uuid; + { + bytes memory data = abi.encode(_marketId, _stakeholderAddress); + address attestor = _getMarketOwner(_marketId); + // Submit attestation for stakeholder to join a market (attestation must be signed by market owner) + uuid = tellerAS.attestByDelegation( + _stakeholderAddress, + _attestingSchemaId, // set by the modifier + _expirationTime, + 0, + data, + attestor, + _v, + _r, + _s + ); + } + _attestStakeholderVerification( + _marketId, + _stakeholderAddress, + uuid, + _isLender + ); + } + + /** + * @notice Adds a stakeholder (borrower/lender) to a market. + * @param _marketId The market ID to add a stakeholder to. + * @param _stakeholderAddress The address of the stakeholder to add to the market. + * @param _uuid The UUID of the attestation created. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _attestStakeholderVerification( + uint256 _marketId, + address _stakeholderAddress, + bytes32 _uuid, + bool _isLender + ) internal virtual { + if (_isLender) { + // Store the lender attestation ID for the market ID + markets[_marketId].lenderAttestationIds[ + _stakeholderAddress + ] = _uuid; + // Add lender address to market set + markets[_marketId].verifiedLendersForMarket.add( + _stakeholderAddress + ); + + emit LenderAttestation(_marketId, _stakeholderAddress); + } else { + // Store the lender attestation ID for the market ID + markets[_marketId].borrowerAttestationIds[ + _stakeholderAddress + ] = _uuid; + // Add lender address to market set + markets[_marketId].verifiedBorrowersForMarket.add( + _stakeholderAddress + ); + + emit BorrowerAttestation(_marketId, _stakeholderAddress); + } + } + + /** + * @notice Removes a stakeholder from an market. + * @dev The caller must be the market owner. + * @param _marketId The market ID to remove the borrower from. + * @param _stakeholderAddress The address of the borrower to remove from the market. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _revokeStakeholder( + uint256 _marketId, + address _stakeholderAddress, + bool _isLender + ) internal virtual { + require( + _msgSender() == _getMarketOwner(_marketId), + "Not the market owner" + ); + + bytes32 uuid = _revokeStakeholderVerification( + _marketId, + _stakeholderAddress, + _isLender + ); + // NOTE: Disabling the call to revoke the attestation on EAS contracts + // tellerAS.revoke(uuid); + } + + /** + * @notice Removes a stakeholder from an market via delegated revocation. + * @param _marketId The market ID to remove the borrower from. + * @param _stakeholderAddress The address of the borrower to remove from the market. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + * @param _v Signature value + * @param _r Signature value + * @param _s Signature value + */ + function _revokeStakeholderViaDelegation( + uint256 _marketId, + address _stakeholderAddress, + bool _isLender, + uint8 _v, + bytes32 _r, + bytes32 _s + ) internal { + bytes32 uuid = _revokeStakeholderVerification( + _marketId, + _stakeholderAddress, + _isLender + ); + // NOTE: Disabling the call to revoke the attestation on EAS contracts + // address attestor = markets[_marketId].owner; + // tellerAS.revokeByDelegation(uuid, attestor, _v, _r, _s); + } + + /** + * @notice Removes a stakeholder (borrower/lender) from a market. + * @param _marketId The market ID to remove the lender from. + * @param _stakeholderAddress The address of the stakeholder to remove from the market. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + * @return uuid_ The ID of the previously verified attestation. + */ + function _revokeStakeholderVerification( + uint256 _marketId, + address _stakeholderAddress, + bool _isLender + ) internal virtual returns (bytes32 uuid_) { + if (_isLender) { + uuid_ = markets[_marketId].lenderAttestationIds[ + _stakeholderAddress + ]; + // Remove lender address from market set + markets[_marketId].verifiedLendersForMarket.remove( + _stakeholderAddress + ); + + emit LenderRevocation(_marketId, _stakeholderAddress); + } else { + uuid_ = markets[_marketId].borrowerAttestationIds[ + _stakeholderAddress + ]; + // Remove borrower address from market set + markets[_marketId].verifiedBorrowersForMarket.remove( + _stakeholderAddress + ); + + emit BorrowerRevocation(_marketId, _stakeholderAddress); + } + } + + /** + * @notice Checks if a stakeholder has been attested and added to a market. + * @param _stakeholderAddress Address of the stakeholder to check. + * @param _attestationRequired Stored boolean indicating if attestation is required for the stakeholder class. + * @param _stakeholderAttestationIds Mapping of attested Ids for the stakeholder class. + */ + function _isVerified( + address _stakeholderAddress, + bool _attestationRequired, + mapping(address => bytes32) storage _stakeholderAttestationIds, + EnumerableSet.AddressSet storage _verifiedStakeholderForMarket + ) internal view virtual returns (bool isVerified_, bytes32 uuid_) { + if (_attestationRequired) { + isVerified_ = + _verifiedStakeholderForMarket.contains(_stakeholderAddress) && + tellerAS.isAttestationActive( + _stakeholderAttestationIds[_stakeholderAddress] + ); + uuid_ = _stakeholderAttestationIds[_stakeholderAddress]; + } else { + isVerified_ = true; + } + } +} diff --git a/packages/contracts/contracts/MarketRegistry_G2.sol b/packages/contracts/contracts/MarketRegistry_G2.sol new file mode 100644 index 000000000..087d5aaca --- /dev/null +++ b/packages/contracts/contracts/MarketRegistry_G2.sol @@ -0,0 +1,1198 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Contracts +//import "./EAS/TellerAS.sol"; +//import "./EAS/TellerASResolver.sol"; + +//must continue to use this so storage slots are not broken +import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; + +// Interfaces + +import "./interfaces/IMarketRegistry_V2.sol"; + +// Libraries +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import { PaymentType } from "./libraries/V2Calculations.sol"; + +contract MarketRegistry_G2 is + IMarketRegistry_V2, + Initializable, + Context +{ + using EnumerableSet for EnumerableSet.AddressSet; + + /** Constant Variables **/ + + uint256 public constant CURRENT_CODE_VERSION = 9; + + /* Storage Variables */ + + struct Marketplace { + address owner; + string metadataURI; + uint16 marketplaceFeePercent; //DEPRECATED + bool lenderAttestationRequired; + EnumerableSet.AddressSet verifiedLendersForMarket; + mapping(address => bytes32) _lenderAttestationIds; //DEPRECATED + uint32 paymentCycleDuration; //DEPRECATED + uint32 paymentDefaultDuration; //DEPRECATED + uint32 bidExpirationTime; //DEPRECATED + bool borrowerAttestationRequired; + EnumerableSet.AddressSet verifiedBorrowersForMarket; + mapping(address => bytes32) _borrowerAttestationIds; //DEPRECATED + address feeRecipient; //DEPRECATED + PaymentType paymentType; //DEPRECATED + PaymentCycleType paymentCycleType; //DEPRECATED + } + + bytes32 public __lenderAttestationSchemaId; //DEPRECATED + + mapping(uint256 => Marketplace) internal markets; + mapping(bytes32 => uint256) internal __uriToId; //DEPRECATED + uint256 public marketCount; + bytes32 private _attestingSchemaId; + bytes32 public borrowerAttestationSchemaId; + + uint256 public version; + + mapping(uint256 => bool) private marketIsClosed; + + + + //TellerAS public tellerAS; //this took 7 storage slots + uint256[7] private __teller_as_gap; + + //uint256 marketTermsCount; // use a hash here instead of uint256 + mapping(bytes32 => MarketplaceTerms) public marketTerms; + + //market id => market terms. Used when a new bid is created. If this is blank for a market, new bids cant be created for that market. + mapping(uint256 => bytes32) public currentMarketTermsForMarket; + + /* Modifiers */ + + modifier ownsMarket(uint256 _marketId) { + require(_getMarketOwner(_marketId) == _msgSender(), "Not the owner"); + _; + } + + /* modifier withAttestingSchema(bytes32 schemaId) { + _attestingSchemaId = schemaId; + _; + _attestingSchemaId = bytes32(0); + }*/ + + /* Events */ + + event MarketCreated(address indexed owner, uint256 marketId); + event SetMarketURI(uint256 marketId, string uri); + event SetPaymentCycleDuration(uint256 marketId, uint32 duration); // DEPRECATED - used for subgraph reference + event SetPaymentCycle( + uint256 marketId, + PaymentCycleType paymentCycleType, + uint32 value + ); + event SetPaymentDefaultDuration(uint256 marketId, uint32 duration); + event SetBidExpirationTime(uint256 marketId, uint32 duration); + event SetMarketFee(uint256 marketId, uint16 feePct); + event LenderAttestation(uint256 marketId, address lender); + event BorrowerAttestation(uint256 marketId, address borrower); + event LenderRevocation(uint256 marketId, address lender); + event BorrowerRevocation(uint256 marketId, address borrower); + event MarketClosed(uint256 marketId); + event LenderExitMarket(uint256 marketId, address lender); + event BorrowerExitMarket(uint256 marketId, address borrower); + event SetMarketOwner(uint256 marketId, address newOwner); + event SetMarketFeeRecipient(uint256 marketId, address newRecipient); + event SetMarketLenderAttestation(uint256 marketId, bool required); + event SetMarketBorrowerAttestation(uint256 marketId, bool required); + event SetMarketPaymentType(uint256 marketId, PaymentType paymentType); + + event DefineMarketTerms(bytes32 marketTermsId); + event SetCurrentMarketTermsForMarket( + uint256 marketId, + bytes32 marketTermsId + ); + + /* External Functions */ + + function initialize() external initializer { + /* tellerAS = _tellerAS; + + lenderAttestationSchemaId = tellerAS.getASRegistry().register( + "(uint256 marketId, address lenderAddress)", + this + ); + borrowerAttestationSchemaId = tellerAS.getASRegistry().register( + "(uint256 marketId, address borrowerAddress)", + this + ); */ + } + + /** + * @notice Creates a new market. + * @param _initialOwner Address who will initially own the market. + + * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. + * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. + + * @param _uri URI string to get metadata details about the market. + * @param _marketTermsParams Parameters to define the market terms. + + * @return marketId_ The market ID of the newly created market. + * @return marketTerms_ The market Terms Hash of the markets terms. + */ + function createMarket( + address _initialOwner, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + string calldata _uri, + MarketplaceTerms memory _marketTermsParams + ) external returns (uint256 marketId_, bytes32 marketTerms_) { + marketId_ = _createMarket( + _initialOwner, + _requireLenderAttestation, + _requireBorrowerAttestation, + _uri + ); + + marketTerms_ = _updateMarketSettings(marketId_, _marketTermsParams); + } + + /** + * @notice Creates a new market. + * @param _initialOwner Address who will initially own the market. + + * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market. + * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market. + + * @param _uri URI string to get metadata details about the market. + * @return marketId_ The market ID of the newly created market. + */ + function _createMarket( + address _initialOwner, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + string calldata _uri + ) internal returns (uint256 marketId_) { + require(_initialOwner != address(0), "Invalid owner address"); + // Increment market ID counter + marketId_ = ++marketCount; + + // Set the market owner + markets[marketId_].owner = _initialOwner; + markets[marketId_].metadataURI = _uri; + markets[marketId_] + .borrowerAttestationRequired = _requireBorrowerAttestation; + markets[marketId_] + .lenderAttestationRequired = _requireLenderAttestation; + + emit MarketCreated(_initialOwner, marketId_); + } + + /** + * @notice Closes a market so new bids cannot be added. + * @param _marketId The market ID for the market to close. + */ + + function closeMarket(uint256 _marketId) public ownsMarket(_marketId) { + if (!marketIsClosed[_marketId]) { + marketIsClosed[_marketId] = true; + + emit MarketClosed(_marketId); + } + } + + /** + * @notice Returns the status of a market existing and not being closed. + * @param _marketId The market ID for the market to check. + */ + function isMarketOpen(uint256 _marketId) + public + view + override + returns (bool) + { + return + markets[_marketId].owner != address(0) && + !marketIsClosed[_marketId]; + } + + /** + * @notice Returns the status of a market being open or closed for new bids. Does not indicate whether or not a market exists. + * @param _marketId The market ID for the market to check. + */ + function isMarketClosed(uint256 _marketId) + public + view + override + returns (bool) + { + return marketIsClosed[_marketId]; + } + + /** + * @notice Transfers ownership of a marketplace. + * @param _marketId The ID of a market. + * @param _newOwner Address of the new market owner. + * + * Requirements: + * - The caller must be the current owner. + */ + function transferMarketOwnership(uint256 _marketId, address _newOwner) + public + ownsMarket(_marketId) + { + markets[_marketId].owner = _newOwner; + emit SetMarketOwner(_marketId, _newOwner); + } + + /** + * @notice Updates multiple market settings for a given market. Does not affect existing bids only new ones created after. + * @param _marketId The ID of a market. + + * @param _marketTermsParams The new parameters to use for the market terms + * + * Requirements: + * - The caller must be the current owner. + */ + function updateMarketSettings( + uint256 _marketId, + MarketplaceTerms memory _marketTermsParams + ) public ownsMarket(_marketId) returns (bytes32 marketTermsId_) { + return _updateMarketSettings(_marketId, _marketTermsParams); + } + + function _updateMarketSettings( + uint256 _marketId, + MarketplaceTerms memory _marketTermsParams + ) internal returns (bytes32 marketTermsId_) { + marketTermsId_ = _defineNewMarketTermsRevision( + _marketTermsParams.paymentCycleDuration, + _marketTermsParams.paymentType, + _marketTermsParams.paymentCycleType, + _marketTermsParams.paymentDefaultDuration, + _marketTermsParams.bidExpirationTime, + _marketTermsParams.marketplaceFeePercent, + _marketTermsParams.feeRecipient + ); + emit DefineMarketTerms(marketTermsId_); + + currentMarketTermsForMarket[_marketId] = marketTermsId_; + emit SetCurrentMarketTermsForMarket(_marketId, marketTermsId_); + } + + function marketHasDefinedTerms(uint256 _marketId) + public + view + returns (bool) + { + return currentMarketTermsForMarket[_marketId] != bytes32(0); + } + + function getCurrentTermsForMarket(uint256 _marketId) + public + view + returns (bytes32) + { + return currentMarketTermsForMarket[_marketId]; + } + + /** + * @notice Sets the metadata URI for a market. + * @param _marketId The ID of a market. + * @param _uri A URI that points to a market's metadata. + * + * Requirements: + * - The caller must be the current owner. + */ + function setMarketURI(uint256 _marketId, string calldata _uri) + public + ownsMarket(_marketId) + { + //We do string comparison by checking the hashes of the strings against one another + if ( + keccak256(abi.encodePacked(_uri)) != + keccak256(abi.encodePacked(markets[_marketId].metadataURI)) + ) { + markets[_marketId].metadataURI = _uri; + + emit SetMarketURI(_marketId, _uri); + } + } + + //need to rebuild this + /** + * @notice Gets the data associated with a market. + * @param _marketId The ID of a market. + */ + function getMarketData(uint256 _marketId) + public + view + returns ( + address owner, + string memory metadataURI, + bool borrowerAttestationRequired, + bool lenderAttestationRequired, + bytes32 marketTermsId + ) + { + return ( + markets[_marketId].owner, + markets[_marketId].metadataURI, + markets[_marketId].borrowerAttestationRequired, + markets[_marketId].lenderAttestationRequired, + currentMarketTermsForMarket[_marketId] + ); + } + + function getMarketTermsData(bytes32 _marketTermsId) + public + view + returns ( + uint32 paymentCycleDuration, + PaymentType paymentType, + PaymentCycleType paymentCycleType, + uint32 paymentDefaultDuration, + uint32 bidExpirationTime, + uint16 feePercent, + address feeRecipient + ) + { + + return ( + getPaymentCycleDurationForTerms(_marketTermsId), + marketTerms[_marketTermsId].paymentType, + marketTerms[_marketTermsId].paymentCycleType, + marketTerms[_marketTermsId].paymentDefaultDuration, + marketTerms[_marketTermsId].bidExpirationTime, + marketTerms[_marketTermsId].marketplaceFeePercent, + marketTerms[_marketTermsId].feeRecipient + ); + } + + /** + * @notice Gets the attestation requirements for a given market. + * @param _marketId The ID of the market. + */ + function getMarketAttestationRequirements(uint256 _marketId) + public + view + returns ( + bool lenderAttestationRequired, + bool borrowerAttestationRequired + ) + { + return ( + markets[_marketId].lenderAttestationRequired, + markets[_marketId].borrowerAttestationRequired + ); + } + + /** + * @notice Gets the address of a market's owner. + * @param _marketId The ID of a market. + * @return The address of a market's owner. + */ + function getMarketOwner(uint256 _marketId) + public + view + virtual + override + returns (address) + { + return _getMarketOwner(_marketId); + } + + /** + * @notice Gets the address of a market's owner. + * @param _marketId The ID of a market. + * @return The address of a market's owner. + */ + function _getMarketOwner(uint256 _marketId) + internal + view + virtual + returns (address) + { + return markets[_marketId].owner; + } + + /** + * @notice Gets the metadata URI of a market. + * @param _marketId The ID of a market. + * @return URI of a market's metadata. + */ + function getMarketURI(uint256 _marketId) + public + view + override + returns (string memory) + { + return markets[_marketId].metadataURI; + } + + /** + * @notice Gets the current marketplace fee of a market. This is a carryover to support legacy contracts + * @dev This is current marketplace fee if a NEW LOAN is created NOT the fee for any legacy loans in this market + * @param _marketId The ID of a market. + * @return URI of a market's metadata. + */ + function getMarketplaceFee(uint256 _marketId) + external + view + returns (uint16) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + return marketTerms[_marketTermsId].marketplaceFeePercent; + } + + function getMarketFeeRecipient(uint256 _marketId) + external + view + returns (address _recipient) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + _recipient= marketTerms[_marketTermsId].feeRecipient; + + + if (_recipient == address(0)) { + return _getMarketOwner(_marketId); + } + } + + + + + /** + * @notice Gets the loan default duration of a market. + * @param _marketId The ID of the market. + * @return Duration of a loan repayment interval until it is default. + */ + function getPaymentDefaultDuration(uint256 _marketId) + public + view + returns (uint32) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + return marketTerms[_marketTermsId].paymentDefaultDuration; + } + + /** + * @notice Get the payment type of a market. + * @param _marketId The ID of the market. + * @return The type of payment for loans in the market. + */ + function getPaymentType(uint256 _marketId) + public + view + returns (PaymentType) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + return marketTerms[_marketTermsId].paymentType; + } + + function getPaymentCycleType(uint256 _marketId) + public + view + returns (PaymentCycleType) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + return marketTerms[_marketTermsId].paymentCycleType; + } + + function getPaymentCycleDuration(uint256 _marketId) + public + view + returns (uint32) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + return getPaymentCycleDurationForTerms(_marketTermsId); + } + + /** + * @notice Gets the loan default duration of a market. + * @param _marketId The ID of the market. + * @return Expiration of a loan bid submission until it is no longer acceptable. + */ + function getBidExpirationTime(uint256 _marketId) + public + view + returns ( + //override + uint32 + ) + { + bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId]; + return marketTerms[_marketTermsId].bidExpirationTime; + } + + + + + function getMarketFeeTerms(bytes32 _marketTermsId) + public + view + returns (address, uint16) + { + return ( + marketTerms[_marketTermsId].feeRecipient, + marketTerms[_marketTermsId].marketplaceFeePercent + ); + } + + function getMarketTermsForLending(bytes32 _marketTermsId) + public + view + returns (uint32, PaymentCycleType, PaymentType, uint32, uint32) + { + require(_marketTermsId != bytes32(0), "Invalid market terms."); + + uint32 paymentCycleDuration = getPaymentCycleDurationForTerms(_marketTermsId); + + return ( + paymentCycleDuration, + marketTerms[_marketTermsId].paymentCycleType, + marketTerms[_marketTermsId].paymentType, + marketTerms[_marketTermsId].paymentDefaultDuration, + marketTerms[_marketTermsId].bidExpirationTime + ); + } + + + + + /** + * @notice Gets the loan default duration of a market. + * @param _marketTermsId The ID of the market terms. + * @return Duration of a loan repayment interval until it is default. + */ + function getPaymentDefaultDurationForTerms(bytes32 _marketTermsId) + public + view + returns (uint32) + { + return marketTerms[_marketTermsId].paymentDefaultDuration; + } + + /** + * @notice Get the payment type of a market. + * @param _marketTermsId the ID of the market terms. + * @return The type of payment for loans in the market. + */ + function getPaymentTypeForTerms(bytes32 _marketTermsId) + public + view + returns (PaymentType) + { + return marketTerms[_marketTermsId].paymentType; + } + + function getPaymentCycleTypeForTerms(bytes32 _marketTermsId) + public + view + returns (PaymentCycleType) + { + return marketTerms[_marketTermsId].paymentCycleType; + } + + function getPaymentCycleDurationForTerms(bytes32 _marketTermsId) + public + view + returns (uint32) + { + if(marketTerms[_marketTermsId].paymentCycleType == PaymentCycleType.Monthly){ + return 30 days; + } + + return marketTerms[_marketTermsId].paymentCycleDuration; + } + + /** + * @notice Gets the loan default duration of a market. + * @param _marketTermsId The ID of the market terms. + * @return Expiration of a loan bid submission until it is no longer acceptable. + */ + function getBidExpirationTimeForTerms(bytes32 _marketTermsId) + public + view + returns ( + //override + uint32 + ) + { + return marketTerms[_marketTermsId].bidExpirationTime; + } + + /** + * @notice Checks if a lender has been attested and added to a market. + * @param _marketId The ID of a market. + * @param _lender Address to check. + * @return isVerified_ Boolean indicating if a lender has been added to a market. + * @return uuid_ This is now deprecated and blank + */ + function isVerifiedLender(uint256 _marketId, address _lender) + public + view + override + returns (bool isVerified_, bytes32 uuid_) + { + isVerified_ = _isVerified( + _lender, + markets[_marketId].lenderAttestationRequired, + //markets[_marketId].lenderAttestationIds, + markets[_marketId].verifiedLendersForMarket + ); + } + + /** + * @notice Checks if a borrower has been attested and added to a market. + * @param _marketId The ID of a market. + * @param _borrower Address of the borrower to check. + * @return isVerified_ Boolean indicating if a borrower has been added to a market. + * @return uuid_ This is now deprecated and blank + */ + function isVerifiedBorrower(uint256 _marketId, address _borrower) + public + view + override + returns (bool isVerified_, bytes32 uuid_) + { + isVerified_ = _isVerified( + _borrower, + markets[_marketId].borrowerAttestationRequired, + //markets[_marketId].borrowerAttestationIds, + markets[_marketId].verifiedBorrowersForMarket + ); + } + + /** + * @notice Gets addresses of all attested lenders. + * @param _marketId The ID of a market. + * @param _page Page index to start from. + * @param _perPage Number of items in a page to return. + * @return Array of addresses that have been added to a market. + */ + function getAllVerifiedLendersForMarket( + uint256 _marketId, + uint256 _page, + uint256 _perPage + ) public view returns (address[] memory) { + EnumerableSet.AddressSet storage set = markets[_marketId] + .verifiedLendersForMarket; + + return _getStakeholdersForMarket(set, _page, _perPage); + } + + /** + * @notice Gets addresses of all attested borrowers. + * @param _marketId The ID of the market. + * @param _page Page index to start from. + * @param _perPage Number of items in a page to return. + * @return Array of addresses that have been added to a market. + */ + function getAllVerifiedBorrowersForMarket( + uint256 _marketId, + uint256 _page, + uint256 _perPage + ) public view returns (address[] memory) { + EnumerableSet.AddressSet storage set = markets[_marketId] + .verifiedBorrowersForMarket; + return _getStakeholdersForMarket(set, _page, _perPage); + } + + /* function _setMarketSettings( + uint256 _marketId, + uint32 _paymentCycleDuration, + PaymentType _newPaymentType, + PaymentCycleType _paymentCycleType, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _borrowerAttestationRequired, + bool _lenderAttestationRequired, + string calldata _metadataURI + ) internal { + setMarketURI(_marketId, _metadataURI); + setPaymentDefaultDuration(_marketId, _paymentDefaultDuration); + setBidExpirationTime(_marketId, _bidExpirationTime); + setMarketFeePercent(_marketId, _feePercent); + setLenderAttestationRequired(_marketId, _lenderAttestationRequired); + setBorrowerAttestationRequired(_marketId, _borrowerAttestationRequired); + setMarketPaymentType(_marketId, _newPaymentType); + setPaymentCycle(_marketId, _paymentCycleType, _paymentCycleDuration); + }*/ + + function _defineNewMarketTermsRevision( + uint32 _paymentCycleDuration, + PaymentType _newPaymentType, + PaymentCycleType _paymentCycleType, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + address _feeRecipient + ) internal returns (bytes32) { + + require( + (_paymentCycleType == PaymentCycleType.Seconds) || + (_paymentCycleType == PaymentCycleType.Monthly && + _paymentCycleDuration == 0), + "Monthly payment cycle duration invalid for cycle type" + ); + + bytes32 marketTermsId = _getMarketTermsHashId( + _paymentCycleDuration, + _newPaymentType, + _paymentCycleType, + _paymentDefaultDuration, + _bidExpirationTime, + _feePercent, + _feeRecipient + ); + + marketTerms[marketTermsId] = MarketplaceTerms({ + paymentCycleDuration: _paymentCycleDuration, + paymentType: _newPaymentType, + paymentCycleType: _paymentCycleType, + paymentDefaultDuration: _paymentDefaultDuration, + bidExpirationTime: _bidExpirationTime, + marketplaceFeePercent: _feePercent, + feeRecipient: _feeRecipient + }); + + return marketTermsId; + } + + function _getMarketTermsHashId( + uint32 _paymentCycleDuration, + PaymentType _newPaymentType, + PaymentCycleType _paymentCycleType, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + address _feeRecipient + ) public view returns (bytes32) { + return + keccak256( + abi.encode( + _paymentCycleDuration, + _newPaymentType, + _paymentCycleType, + _paymentDefaultDuration, + _bidExpirationTime, + _feePercent, + _feeRecipient + ) + ); + } + + //Attestation Functions + +/** + * @notice Enable/disables market whitelist for lenders. + * @param _marketId The ID of a market. + * @param _required Boolean indicating if the market requires whitelist. + * + * Requirements: + * - The caller must be the current owner. + */ + function setLenderAttestationRequired(uint256 _marketId, bool _required) + public + ownsMarket(_marketId) + { + if (_required != markets[_marketId].lenderAttestationRequired) { + markets[_marketId].lenderAttestationRequired = _required; + emit SetMarketLenderAttestation(_marketId, _required); + } + } + + /** + * @notice Enable/disables market whitelist for borrowers. + * @param _marketId The ID of a market. + * @param _required Boolean indicating if the market requires whitelist. + * + * Requirements: + * - The caller must be the current owner. + */ + function setBorrowerAttestationRequired(uint256 _marketId, bool _required) + public + ownsMarket(_marketId) + { + if (_required != markets[_marketId].borrowerAttestationRequired) { + markets[_marketId].borrowerAttestationRequired = _required; + emit SetMarketBorrowerAttestation(_marketId, _required); + } + } + + /** + * @notice Adds a lender to a market. + * @dev See {_attestStakeholder}. + */ + function attestLender( + uint256 _marketId, + address _lenderAddress, + uint256 _expirationTime + ) external { + _attestStakeholder(_marketId, _lenderAddress, _expirationTime, true); + } + + /** + * @notice Removes a lender from an market. + * @dev See {_revokeStakeholder}. + */ + function revokeLender(uint256 _marketId, address _lenderAddress) external { + _revokeStakeholder(_marketId, _lenderAddress, true); + } + + /** + * @notice Allows a lender to voluntarily leave a market. + * @param _marketId The market ID to leave. + */ + function lenderExitMarket(uint256 _marketId) external { + // Remove lender address from market set + bool response = markets[_marketId].verifiedLendersForMarket.remove( + _msgSender() + ); + if (response) { + emit LenderExitMarket(_marketId, _msgSender()); + } + } + + /** + * @notice Adds a borrower to a market. + * @dev See {_attestStakeholder}. + */ + function attestBorrower( + uint256 _marketId, + address _borrowerAddress, + uint256 _expirationTime + ) external { + _attestStakeholder(_marketId, _borrowerAddress, _expirationTime, false); + } + + /** + * @notice Removes a borrower from an market. + * @dev See {_revokeStakeholder}. + */ + function revokeBorrower(uint256 _marketId, address _borrowerAddress) + external + { + _revokeStakeholder(_marketId, _borrowerAddress, false); + } + + /** + * @notice Allows a borrower to voluntarily leave a market. + * @param _marketId The market ID to leave. + */ + function borrowerExitMarket(uint256 _marketId) external { + // Remove borrower address from market set + bool response = markets[_marketId].verifiedBorrowersForMarket.remove( + _msgSender() + ); + if (response) { + emit BorrowerExitMarket(_marketId, _msgSender()); + } + } + + /** + * @notice Verifies an attestation is valid. + * @dev This function must only be called by the `attestLender` function above. + * @param recipient Lender's address who is being attested. + * @param schema The schema used for the attestation. + * @param data Data the must include the market ID and lender's address + * @param + * @param attestor Market owner's address who signed the attestation. + * @return Boolean indicating the attestation was successful. + */ + /* function resolve( + address recipient, + bytes calldata schema, + bytes calldata data, + uint256 , // uint256 expirationTime , + address attestor + ) external payable override returns (bool) { + bytes32 attestationSchemaId = keccak256( + abi.encodePacked(schema, address(this)) + ); + (uint256 marketId, address lenderAddress) = abi.decode( + data, + (uint256, address) + ); + return + (_attestingSchemaId == attestationSchemaId && + recipient == lenderAddress && + attestor == _getMarketOwner(marketId)) || + attestor == address(this); + }*/ + + /** + * @notice Gets addresses of all attested relevant stakeholders. + * @param _set The stored set of stakeholders to index from. + * @param _page Page index to start from. + * @param _perPage Number of items in a page to return. + * @return stakeholders_ Array of addresses that have been added to a market. + */ + function _getStakeholdersForMarket( + EnumerableSet.AddressSet storage _set, + uint256 _page, + uint256 _perPage + ) internal view returns (address[] memory stakeholders_) { + uint256 len = _set.length(); + + uint256 start = _page * _perPage; + if (start <= len) { + uint256 end = start + _perPage; + // Ensure we do not go out of bounds + if (end > len) { + end = len; + } + + stakeholders_ = new address[](end - start); + for (uint256 i = start; i < end; i++) { + stakeholders_[i] = _set.at(i); + } + } + } + + /* Internal Functions */ + + /** + * @notice Adds a stakeholder (lender or borrower) to a market. + * @param _marketId The market ID to add a borrower to. + * @param _stakeholderAddress The address of the stakeholder to add to the market. + * @param _expirationTime The expiration time of the attestation. + * @param _expirationTime The expiration time of the attestation. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _attestStakeholder( + uint256 _marketId, + address _stakeholderAddress, + uint256 _expirationTime, + bool _isLender + ) + internal + virtual + /* withAttestingSchema( + _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId + )*/ + { + require( + _msgSender() == _getMarketOwner(_marketId), + "Not the market owner" + ); + + // Submit attestation for borrower to join a market + /* bytes32 uuid = tellerAS.attest( + _stakeholderAddress, + _attestingSchemaId, // set by the modifier + _expirationTime, + 0, + abi.encode(_marketId, _stakeholderAddress) + );*/ + _attestStakeholderVerification( + _marketId, + _stakeholderAddress, + // uuid, + _isLender + ); + } + + /* function _attestStakeholderViaDelegation( + uint256 _marketId, + address _stakeholderAddress, + uint256 _expirationTime, + bool _isLender, + uint8 _v, + bytes32 _r, + bytes32 _s + ) + internal + virtual + withAttestingSchema( + _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId + ) + { + // NOTE: block scope to prevent stack too deep! + bytes32 uuid; + { + bytes memory data = abi.encode(_marketId, _stakeholderAddress); + address attestor = _getMarketOwner(_marketId); + // Submit attestation for stakeholder to join a market (attestation must be signed by market owner) + uuid = tellerAS.attestByDelegation( + _stakeholderAddress, + _attestingSchemaId, // set by the modifier + _expirationTime, + 0, + data, + attestor, + _v, + _r, + _s + ); + } + _attestStakeholderVerification( + _marketId, + _stakeholderAddress, + uuid, + _isLender + ); + }*/ + + /** + * @notice Adds a stakeholder (borrower/lender) to a market. + * @param _marketId The market ID to add a stakeholder to. + * @param _stakeholderAddress The address of the stakeholder to add to the market. + + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _attestStakeholderVerification( + uint256 _marketId, + address _stakeholderAddress, + // bytes32 _uuid, + bool _isLender + ) internal virtual { + if (_isLender) { + // Store the lender attestation ID for the market ID + /* markets[_marketId].lenderAttestationIds[ + _stakeholderAddress + ] = _uuid;*/ + // Add lender address to market set + markets[_marketId].verifiedLendersForMarket.add( + _stakeholderAddress + ); + + emit LenderAttestation(_marketId, _stakeholderAddress); + } else { + // Store the lender attestation ID for the market ID + /* markets[_marketId].borrowerAttestationIds[ + _stakeholderAddress + ] = _uuid;*/ + // Add lender address to market set + markets[_marketId].verifiedBorrowersForMarket.add( + _stakeholderAddress + ); + + emit BorrowerAttestation(_marketId, _stakeholderAddress); + } + } + + /** + * @notice Removes a stakeholder from an market. + * @dev The caller must be the market owner. + * @param _marketId The market ID to remove the borrower from. + * @param _stakeholderAddress The address of the borrower to remove from the market. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _revokeStakeholder( + uint256 _marketId, + address _stakeholderAddress, + bool _isLender + ) internal virtual { + require( + _msgSender() == _getMarketOwner(_marketId), + "Not the market owner" + ); + + _revokeStakeholderVerification( + _marketId, + _stakeholderAddress, + _isLender + ); + + /* bytes32 uuid = _revokeStakeholderVerification( + _marketId, + _stakeholderAddress, + _isLender + );*/ + // NOTE: Disabling the call to revoke the attestation on EAS contracts + // tellerAS.revoke(uuid); + } + + /** + * @notice Removes a stakeholder from an market via delegated revocation. + * @param _marketId The market ID to remove the borrower from. + * @param _stakeholderAddress The address of the borrower to remove from the market. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + * @param _v Signature value + * @param _r Signature value + * @param _s Signature value + */ + /* function _revokeStakeholderViaDelegation( + uint256 _marketId, + address _stakeholderAddress, + bool _isLender, + uint8 _v, + bytes32 _r, + bytes32 _s + ) internal { + bytes32 uuid = _revokeStakeholderVerification( + _marketId, + _stakeholderAddress, + _isLender + ); + // NOTE: Disabling the call to revoke the attestation on EAS contracts + // address attestor = markets[_marketId].owner; + // tellerAS.revokeByDelegation(uuid, attestor, _v, _r, _s); + }*/ + + /** + * @notice Removes a stakeholder (borrower/lender) from a market. + * @param _marketId The market ID to remove the lender from. + * @param _stakeholderAddress The address of the stakeholder to remove from the market. + * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower. + */ + function _revokeStakeholderVerification( + uint256 _marketId, + address _stakeholderAddress, + bool _isLender + ) internal virtual { + if (_isLender) { + /*uuid_ = markets[_marketId].lenderAttestationIds[ + _stakeholderAddress + ];*/ + // Remove lender address from market set + markets[_marketId].verifiedLendersForMarket.remove( + _stakeholderAddress + ); + + emit LenderRevocation(_marketId, _stakeholderAddress); + } else { + /*uuid_ = markets[_marketId].borrowerAttestationIds[ + _stakeholderAddress + ];*/ + // Remove borrower address from market set + markets[_marketId].verifiedBorrowersForMarket.remove( + _stakeholderAddress + ); + + emit BorrowerRevocation(_marketId, _stakeholderAddress); + } + } + + /** + * @notice Checks if a stakeholder has been attested and added to a market. + * @param _stakeholderAddress Address of the stakeholder to check. + * @param _attestationRequired Stored boolean indicating if attestation is required for the stakeholder class. + + */ + function _isVerified( + address _stakeholderAddress, + bool _attestationRequired, + //mapping(address => bytes32) storage _stakeholderAttestationIds, + EnumerableSet.AddressSet storage _verifiedStakeholderForMarket + ) internal view virtual returns (bool isVerified_) { + if (_attestationRequired) { + isVerified_ = _verifiedStakeholderForMarket.contains( + _stakeholderAddress + ); /*&& + tellerAS.isAttestationActive( + _stakeholderAttestationIds[_stakeholderAddress] + );*/ + // uuid_ = _stakeholderAttestationIds[_stakeholderAddress]; + } else { + isVerified_ = true; + } + } +} diff --git a/packages/contracts/contracts/ReputationManager.sol b/packages/contracts/contracts/ReputationManager.sol index 58eff6062..80efeba1c 100644 --- a/packages/contracts/contracts/ReputationManager.sol +++ b/packages/contracts/contracts/ReputationManager.sol @@ -40,48 +40,52 @@ contract ReputationManager is IReputationManager, Initializable { function getDelinquentLoanIds(address _account) public + view override returns (uint256[] memory) { - updateAccountReputation(_account); + //updateAccountReputation(_account); return _delinquencies[_account].values(); } function getDefaultedLoanIds(address _account) public + view override returns (uint256[] memory) { - updateAccountReputation(_account); + //updateAccountReputation(_account); return _defaults[_account].values(); } function getCurrentDelinquentLoanIds(address _account) public + view override returns (uint256[] memory) { - updateAccountReputation(_account); + //updateAccountReputation(_account); return _currentDelinquencies[_account].values(); } function getCurrentDefaultLoanIds(address _account) public + view override returns (uint256[] memory) { - updateAccountReputation(_account); + //updateAccountReputation(_account); return _currentDefaults[_account].values(); } - function updateAccountReputation(address _account) public override { - uint256[] memory activeBidIds = tellerV2.getBorrowerActiveLoanIds( + /*function updateAccountReputation(address _account) public override { + uint256[] memory activeBidIds = tellerV2.getBorrowerActiveLoanIds( _account ); for (uint256 i; i < activeBidIds.length; i++) { _applyReputation(_account, activeBidIds[i]); } - } + }*/ function updateAccountReputation(address _account, uint256 _bidId) public diff --git a/packages/contracts/contracts/TellerV2.sol b/packages/contracts/contracts/TellerV2.sol index bfcbc28bf..489332002 100644 --- a/packages/contracts/contracts/TellerV2.sol +++ b/packages/contracts/contracts/TellerV2.sol @@ -13,7 +13,7 @@ import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "./interfaces/ICollateralManager.sol"; // Interfaces -import "./interfaces/IMarketRegistry.sol"; +import "./interfaces/IMarketRegistry_V2.sol"; import "./interfaces/IReputationManager.sol"; import "./interfaces/ITellerV2.sol"; import { Collateral } from "./interfaces/escrow/ICollateralEscrowV1.sol"; @@ -26,6 +26,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./libraries/NumbersLib.sol"; import { V2Calculations, PaymentCycleType } from "./libraries/V2Calculations.sol"; + /* Errors */ /** @@ -134,6 +135,11 @@ contract TellerV2 is uint256 indexed amount ); + event SetBidMarketTerms( + uint256 indexed bidId, + bytes32 indexed marketTermsId + ); + /** Modifiers */ /** @@ -202,7 +208,7 @@ contract TellerV2 is _marketRegistry.isContract(), "MarketRegistry must be a contract" ); - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); require( _reputationManager.isContract(), @@ -215,10 +221,10 @@ contract TellerV2 is _setCollateralManagerV2(_collateralManagerV2); } - function setCollateralManagerV2(address _collateralManagerV2) - external - reinitializer(10) - { + function setCollateralManagerV2( + address _collateralManagerV2 + ) external reinitializer(10) { + require(address(_collateralManagerV2) == address(0)); _setCollateralManagerV2(_collateralManagerV2); } @@ -227,10 +233,9 @@ contract TellerV2 is escrowVault = IEscrowVault(_escrowVault); } - function _setLenderManager(address _lenderManager) - internal - onlyInitializing - { + function _setLenderManager( + address _lenderManager + ) internal onlyInitializing { require( _lenderManager.isContract(), "LenderManager must be a contract" @@ -238,10 +243,9 @@ contract TellerV2 is lenderManager = ILenderManager(_lenderManager); } - function _setCollateralManagerV2(address _collateralManagerV2) - internal - onlyInitializing - { + function _setCollateralManagerV2( + address _collateralManagerV2 + ) internal onlyInitializing { require( _collateralManagerV2.isContract(), "CollateralManagerV2 must be a contract" @@ -254,11 +258,9 @@ contract TellerV2 is * @param _bidId The id of the bid to return the metadataURI for * @return metadataURI_ The metadataURI for the bid, as a string. */ - function getMetadataURI(uint256 _bidId) - public - view - returns (string memory metadataURI_) - { + function getMetadataURI( + uint256 _bidId + ) public view returns (string memory metadataURI_) { // Check uri mapping first metadataURI_ = uris[_bidId]; // If the URI is not present in the mapping @@ -355,12 +357,14 @@ contract TellerV2 is ) internal virtual returns (uint256 bidId_) { address sender = _msgSenderForMarket(_marketplaceId); - (bool isVerified, ) = marketRegistry.isVerifiedBorrower( - _marketplaceId, - sender - ); + { + (bool isVerified, ) = marketRegistry.isVerifiedBorrower( + _marketplaceId, + sender + ); - require(isVerified, "Not verified borrower"); + require(isVerified, "Not verified borrower"); + } require( marketRegistry.isMarketOpen(_marketplaceId), @@ -368,10 +372,10 @@ contract TellerV2 is ); // Set response bid ID. - bidId_ = bidId; + bidId_ = nextBidId; // Create and store our bid into the mapping - Bid storage bid = bids[bidId]; + Bid storage bid = bids[nextBidId]; bid.borrower = sender; bid.receiver = _receiver != address(0) ? _receiver : bid.borrower; bid.marketplaceId = _marketplaceId; @@ -381,49 +385,57 @@ contract TellerV2 is bid.loanDetails.timestamp = uint32(block.timestamp); //make this new bid use the most recent version of collateral manager - collateralManagerForBid[bidId] = address(collateralManagerV2); + collateralManagerForBid[bidId_] = address(collateralManagerV2); // Set payment cycle type based on market setting (custom or monthly) - (bid.terms.paymentCycle, bidPaymentCycleType[bidId]) = marketRegistry - .getPaymentCycle(_marketplaceId); - - bid.terms.APR = _APR; - bidDefaultDuration[bidId] = marketRegistry.getPaymentDefaultDuration( + bidMarketTermsId[bidId_] = marketRegistry.getCurrentTermsForMarket( _marketplaceId - ); + ); - bidExpirationTime[bidId] = marketRegistry.getBidExpirationTime( - _marketplaceId - ); + require(bidMarketTermsId[bidId_] != bytes32(0), "Market does not have assigned terms."); + + ( + uint32 paymentCycleDuration, + PaymentCycleType paymentCycleType, + PaymentType paymentType, + , + + ) = marketRegistry.getMarketTermsForLending(bidMarketTermsId[bidId_]); + - bid.paymentType = marketRegistry.getPaymentType(_marketplaceId); + bid.terms.APR = _APR; bid.terms.paymentCycleAmount = V2Calculations .calculatePaymentCycleAmount( - bid.paymentType, - bidPaymentCycleType[bidId], + paymentType, + paymentCycleType, _principal, _duration, - bid.terms.paymentCycle, + paymentCycleDuration, _APR ); - uris[bidId] = _metadataURI; + //uris[bidId] = _metadataURI; bid.state = BidState.PENDING; emit SubmittedBid( - bidId, + bidId_, bid.borrower, bid.receiver, keccak256(abi.encodePacked(_metadataURI)) ); + emit SetBidMarketTerms( + bidId_, + bidMarketTermsId[bidId_] + ); + // Store bid inside borrower bids mapping - borrowerBids[bid.borrower].push(bidId); + //borrowerBids[bid.borrower].push(bidId); // Increment bid id counter - bidId++; + nextBidId++; } /** @@ -467,11 +479,9 @@ contract TellerV2 is * @notice Function for users to cancel a bid. * @param _bidId The id of the bid to be cancelled. */ - function _cancelBid(uint256 _bidId) - internal - virtual - pendingBid(_bidId, "cancelBid") - { + function _cancelBid( + uint256 _bidId + ) internal virtual pendingBid(_bidId, "cancelBid") { // Set the bid state to CANCELLED bids[_bidId].state = BidState.CANCELLED; @@ -483,7 +493,9 @@ contract TellerV2 is * @notice Function for a lender to accept a proposed loan bid. * @param _bidId The id of the loan bid to accept. */ - function lenderAcceptBid(uint256 _bidId) + function lenderAcceptBid( + uint256 _bidId + ) external override pendingBid(_bidId, "lenderAcceptBid") @@ -497,12 +509,18 @@ contract TellerV2 is // Retrieve bid Bid storage bid = bids[_bidId]; + address sender = _msgSenderForMarket(bid.marketplaceId); + + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + + //bytes32 currentMarketplaceTermsId = marketRegistry.getCurrentTermsForMarket(_marketplaceId); (bool isVerified, ) = marketRegistry.isVerifiedLender( bid.marketplaceId, sender ); + require(isVerified, "Not verified lender"); require( @@ -529,11 +547,14 @@ contract TellerV2 is collateralManagerV2.depositCollateral(_bidId); } + (address marketFeeRecipient, uint16 marketFee) = marketRegistry + .getMarketFeeTerms(bidTermsId); + + + // Transfer funds to borrower from the lender amountToProtocol = bid.loanDetails.principal.percent(protocolFee()); - amountToMarketplace = bid.loanDetails.principal.percent( - marketRegistry.getMarketplaceFee(bid.marketplaceId) - ); + amountToMarketplace = bid.loanDetails.principal.percent(marketFee); amountToBorrower = bid.loanDetails.principal - amountToProtocol - @@ -552,18 +573,18 @@ contract TellerV2 is if (amountToMarketplace > 0) { bid.loanDetails.lendingToken.safeTransferFrom( sender, - marketRegistry.getMarketFeeRecipient(bid.marketplaceId), + marketFeeRecipient, amountToMarketplace ); } //transfer funds to borrower if (amountToBorrower > 0) { - bid.loanDetails.lendingToken.safeTransferFrom( + bid.loanDetails.lendingToken.safeTransferFrom( sender, bid.receiver, amountToBorrower - ); + ); } // Record volume filled by lenders @@ -575,7 +596,7 @@ contract TellerV2 is .principal; // Add borrower's active bid - _borrowerBidsActive[bid.borrower].add(_bidId); + //_borrowerBidsActive[bid.borrower].add(_bidId); // Emit AcceptedBid emit AcceptedBid(_bidId, sender); @@ -584,11 +605,9 @@ contract TellerV2 is emit FeePaid(_bidId, "marketplace", amountToMarketplace); } - function claimLoanNFT(uint256 _bidId) - external - acceptedLoan(_bidId, "claimLoanNFT") - whenNotPaused - { + function claimLoanNFT( + uint256 _bidId + ) external acceptedLoan(_bidId, "claimLoanNFT") whenNotPaused { // Retrieve bid Bid storage bid = bids[_bidId]; @@ -606,10 +625,9 @@ contract TellerV2 is * @notice Function for users to make the minimum amount due for an active loan. * @param _bidId The id of the loan to make the payment towards. */ - function repayLoanMinimum(uint256 _bidId) - external - acceptedLoan(_bidId, "repayLoan") - { + function repayLoanMinimum( + uint256 _bidId + ) external acceptedLoan(_bidId, "repayLoan") { ( uint256 owedPrincipal, uint256 duePrincipal, @@ -617,7 +635,8 @@ contract TellerV2 is ) = V2Calculations.calculateAmountOwed( bids[_bidId], block.timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); _repayLoan( _bidId, @@ -631,10 +650,9 @@ contract TellerV2 is * @notice Function for users to repay an active loan in full. * @param _bidId The id of the loan to make the payment towards. */ - function repayLoanFull(uint256 _bidId) - external - acceptedLoan(_bidId, "repayLoan") - { + function repayLoanFull( + uint256 _bidId + ) external acceptedLoan(_bidId, "repayLoan") { _repayLoanFull(_bidId, true); } @@ -644,10 +662,10 @@ contract TellerV2 is * @param _bidId The id of the loan to make the payment towards. * @param _amount The amount of the payment. */ - function repayLoan(uint256 _bidId, uint256 _amount) - external - acceptedLoan(_bidId, "repayLoan") - { + function repayLoan( + uint256 _bidId, + uint256 _amount + ) external acceptedLoan(_bidId, "repayLoan") { _repayLoanAtleastMinimum(_bidId, _amount, true); } @@ -655,26 +673,27 @@ contract TellerV2 is * @notice Function for users to repay an active loan in full. * @param _bidId The id of the loan to make the payment towards. */ - function repayLoanFullWithoutCollateralWithdraw(uint256 _bidId) - external - acceptedLoan(_bidId, "repayLoan") - { + function repayLoanFullWithoutCollateralWithdraw( + uint256 _bidId + ) external acceptedLoan(_bidId, "repayLoan") { _repayLoanFull(_bidId, false); } - function repayLoanWithoutCollateralWithdraw(uint256 _bidId, uint256 _amount) - external - acceptedLoan(_bidId, "repayLoan") - { + function repayLoanWithoutCollateralWithdraw( + uint256 _bidId, + uint256 _amount + ) external acceptedLoan(_bidId, "repayLoan") { _repayLoanAtleastMinimum(_bidId, _amount, false); } function _repayLoanFull(uint256 _bidId, bool withdrawCollateral) internal { + (uint256 owedPrincipal, , uint256 interest) = V2Calculations .calculateAmountOwed( bids[_bidId], block.timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); _repayLoan( _bidId, @@ -696,7 +715,8 @@ contract TellerV2 is ) = V2Calculations.calculateAmountOwed( bids[_bidId], block.timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); uint256 minimumOwed = duePrincipal + interest; @@ -731,10 +751,9 @@ contract TellerV2 is * @notice Function for lender to claim collateral for a defaulted loan. The only purpose of a CLOSED loan is to make collateral claimable by lender. * @param _bidId The id of the loan to set to CLOSED status. */ - function lenderCloseLoan(uint256 _bidId) - external - acceptedLoan(_bidId, "lenderClaimCollateral") - { + function lenderCloseLoan( + uint256 _bidId + ) external acceptedLoan(_bidId, "lenderClaimCollateral") { require(isLoanDefaulted(_bidId), "Loan must be defaulted."); Bid storage bid = bids[_bidId]; @@ -750,10 +769,9 @@ contract TellerV2 is * @notice Function for users to liquidate a defaulted loan. * @param _bidId The id of the loan to make the payment towards. */ - function liquidateLoanFull(uint256 _bidId) - external - acceptedLoan(_bidId, "liquidateLoan") - { + function liquidateLoanFull( + uint256 _bidId + ) external acceptedLoan(_bidId, "liquidateLoan") { require(isLoanLiquidateable(_bidId), "Loan must be liquidateable."); Bid storage bid = bids[_bidId]; @@ -765,7 +783,8 @@ contract TellerV2 is .calculateAmountOwed( bid, block.timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); //this sets the state to 'repaid' @@ -817,7 +836,7 @@ contract TellerV2 is } // Remove borrower's active bid - _borrowerBidsActive[bid.borrower].remove(_bidId); + //_borrowerBidsActive[bid.borrower].remove(_bidId); // If loan is is being liquidated and backed by collateral, withdraw and send to borrower if (_shouldWithdrawCollateral) { @@ -844,9 +863,10 @@ contract TellerV2 is } } - function _sendOrEscrowFunds(uint256 _bidId, uint256 _paymentAmount) - internal - { + function _sendOrEscrowFunds( + uint256 _bidId, + uint256 _paymentAmount + ) internal { Bid storage bid = bids[_bidId]; address lender = getLoanLender(_bidId); @@ -898,11 +918,10 @@ contract TellerV2 is * @param _bidId The id of the loan bid to calculate the owed amount for. * @param _timestamp The timestamp at which to calculate the loan owed amount at. */ - function calculateAmountOwed(uint256 _bidId, uint256 _timestamp) - public - view - returns (Payment memory owed) - { + function calculateAmountOwed( + uint256 _bidId, + uint256 _timestamp + ) public view returns (Payment memory owed) { Bid storage bid = bids[_bidId]; if ( bid.state != BidState.ACCEPTED || @@ -910,7 +929,12 @@ contract TellerV2 is ) return owed; (uint256 owedPrincipal, , uint256 interest) = V2Calculations - .calculateAmountOwed(bid, _timestamp, bidPaymentCycleType[_bidId]); + .calculateAmountOwed( + bid, + _timestamp, + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) + ); owed.principal = owedPrincipal; owed.interest = interest; } @@ -920,11 +944,10 @@ contract TellerV2 is * @param _bidId The id of the loan bid to get the payment amount for. * @param _timestamp The timestamp at which to get the due payment at. */ - function calculateAmountDue(uint256 _bidId, uint256 _timestamp) - public - view - returns (Payment memory due) - { + function calculateAmountDue( + uint256 _bidId, + uint256 _timestamp + ) public view returns (Payment memory due) { Bid storage bid = bids[_bidId]; if ( bids[_bidId].state != BidState.ACCEPTED || @@ -932,7 +955,12 @@ contract TellerV2 is ) return due; (, uint256 duePrincipal, uint256 interest) = V2Calculations - .calculateAmountOwed(bid, _timestamp, bidPaymentCycleType[_bidId]); + .calculateAmountOwed( + bid, + _timestamp, + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) + ); due.principal = duePrincipal; due.interest = interest; } @@ -941,21 +969,19 @@ contract TellerV2 is * @notice Returns the next due date for a loan payment. * @param _bidId The id of the loan bid. */ - function calculateNextDueDate(uint256 _bidId) - public - view - returns (uint32 dueDate_) - { + function calculateNextDueDate( + uint256 _bidId + ) public view returns (uint32 dueDate_) { Bid storage bid = bids[_bidId]; if (bids[_bidId].state != BidState.ACCEPTED) return dueDate_; return V2Calculations.calculateNextDueDate( bid.loanDetails.acceptedTimestamp, - bid.terms.paymentCycle, + _getBidPaymentCycleDuration(_bidId), bid.loanDetails.loanDuration, lastRepaidTimestamp(_bidId), - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId) ); } @@ -973,12 +999,9 @@ contract TellerV2 is * @param _bidId The id of the loan bid to check for. * @return bool True if the loan is defaulted. */ - function isLoanDefaulted(uint256 _bidId) - public - view - override - returns (bool) - { + function isLoanDefaulted( + uint256 _bidId + ) public view override returns (bool) { return _isLoanDefaulted(_bidId, 0); } @@ -987,12 +1010,9 @@ contract TellerV2 is * @param _bidId The id of the loan bid to check for. * @return bool True if the loan is liquidateable. */ - function isLoanLiquidateable(uint256 _bidId) - public - view - override - returns (bool) - { + function isLoanLiquidateable( + uint256 _bidId + ) public view override returns (bool) { return _isLoanDefaulted(_bidId, LIQUIDATION_DELAY); } @@ -1002,17 +1022,16 @@ contract TellerV2 is * @param _additionalDelay Amount of additional seconds after a loan defaulted to allow a liquidation. * @return bool True if the loan is liquidateable. */ - function _isLoanDefaulted(uint256 _bidId, uint32 _additionalDelay) - internal - view - returns (bool) - { + function _isLoanDefaulted( + uint256 _bidId, + uint32 _additionalDelay + ) internal view returns (bool) { Bid storage bid = bids[_bidId]; // Make sure loan cannot be liquidated if it is not active if (bid.state != BidState.ACCEPTED) return false; - uint32 defaultDuration = bidDefaultDuration[_bidId]; + uint32 defaultDuration = _getBidDefaultDuration(_bidId); if (defaultDuration == 0) return false; @@ -1023,21 +1042,15 @@ contract TellerV2 is dueDate + defaultDuration + _additionalDelay; } - function getCollateralManagerForBid(uint256 _bidId) - public - view - virtual - returns (ICollateralManager) - { + function getCollateralManagerForBid( + uint256 _bidId + ) public view virtual returns (ICollateralManager) { return _getCollateralManagerForBid(_bidId); } - function _getCollateralManagerForBid(uint256 _bidId) - internal - view - virtual - returns (ICollateralManager) - { + function _getCollateralManagerForBid( + uint256 _bidId + ) internal view virtual returns (ICollateralManager) { if (collateralManagerForBid[_bidId] == address(0)) { return ICollateralManager(collateralManagerV1); } @@ -1049,16 +1062,13 @@ contract TellerV2 is return address(collateralManagerV2); } - function getBidState(uint256 _bidId) - external - view - override - returns (BidState) - { + function getBidState( + uint256 _bidId + ) external view override returns (BidState) { return bids[_bidId].state; } - function getBorrowerActiveLoanIds(address _borrower) + /* function getBorrowerActiveLoanIds(address _borrower) external view override @@ -1073,7 +1083,7 @@ contract TellerV2 is returns (uint256[] memory) { return borrowerBids[_borrower]; - } + }*/ /** * @notice Checks to see if a pending loan has expired so it is no longer able to be accepted. @@ -1083,10 +1093,63 @@ contract TellerV2 is Bid storage bid = bids[_bidId]; if (bid.state != BidState.PENDING) return false; - if (bidExpirationTime[_bidId] == 0) return false; + if (_getBidExpirationTime(_bidId) == 0) return false; return (uint32(block.timestamp) > - bid.loanDetails.timestamp + bidExpirationTime[_bidId]); + bid.loanDetails.timestamp + _getBidExpirationTime(_bidId)); + } + + function _getBidExpirationTime( + uint256 _bidId + ) internal view returns (uint32) { + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + if (bidTermsId != bytes32(0)) { + return marketRegistry.getBidExpirationTimeForTerms(bidTermsId); + } + + return bidExpirationTime[_bidId]; + } + + function _getBidDefaultDuration( + uint256 _bidId + ) internal view returns (uint32) { + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + if (bidTermsId != bytes32(0)) { + return marketRegistry.getPaymentDefaultDurationForTerms(bidTermsId); + } + + return bidDefaultDuration[_bidId]; + } + + function _getBidPaymentCycleType( + uint256 _bidId + ) internal view returns (PaymentCycleType) { + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + if (bidTermsId != bytes32(0)) { + return marketRegistry.getPaymentCycleTypeForTerms(bidTermsId); + } + + return bidPaymentCycleType[_bidId]; + } + + + + function _getBidPaymentCycleDuration( + uint256 _bidId + ) internal view returns (uint32) { + + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + + + if (bidTermsId != bytes32(0)) { + + return marketRegistry.getPaymentCycleDurationForTerms(bidTermsId); + } + + Bid storage bid = bids[_bidId]; + + + return bid.terms.paymentCycle; } /** @@ -1102,11 +1165,9 @@ contract TellerV2 is * @param _bidId The id of the bid/loan to get the borrower for. * @return borrower_ The address of the borrower associated with the bid. */ - function getLoanBorrower(uint256 _bidId) - public - view - returns (address borrower_) - { + function getLoanBorrower( + uint256 _bidId + ) public view returns (address borrower_) { borrower_ = bids[_bidId].borrower; } @@ -1115,11 +1176,9 @@ contract TellerV2 is * @param _bidId The id of the bid/loan to get the lender for. * @return lender_ The address of the lender associated with the bid. */ - function getLoanLender(uint256 _bidId) - public - view - returns (address lender_) - { + function getLoanLender( + uint256 _bidId + ) public view returns (address lender_) { lender_ = bids[_bidId].lender; if (lender_ == address(USING_LENDER_MANAGER)) { @@ -1132,23 +1191,21 @@ contract TellerV2 is } } - function getLoanLendingToken(uint256 _bidId) - external - view - returns (address token_) - { + function getLoanLendingToken( + uint256 _bidId + ) external view returns (address token_) { token_ = address(bids[_bidId].loanDetails.lendingToken); } - function getLoanMarketId(uint256 _bidId) - external - view - returns (uint256 _marketId) - { + function getLoanMarketId( + uint256 _bidId + ) external view returns (uint256 _marketId) { _marketId = bids[_bidId].marketplaceId; } - function getLoanSummary(uint256 _bidId) + function getLoanSummary( + uint256 _bidId + ) external view returns ( diff --git a/packages/contracts/contracts/TellerV2Storage.sol b/packages/contracts/contracts/TellerV2Storage.sol index c2e190828..242e97b12 100644 --- a/packages/contracts/contracts/TellerV2Storage.sol +++ b/packages/contracts/contracts/TellerV2Storage.sol @@ -1,7 +1,7 @@ pragma solidity >=0.8.0 <0.9.0; // SPDX-License-Identifier: MIT -import { IMarketRegistry } from "./interfaces/IMarketRegistry.sol"; +import { IMarketRegistry_V2 } from "./interfaces/IMarketRegistry_V2.sol"; import "./interfaces/IEscrowVault.sol"; import "./interfaces/IReputationManager.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; @@ -51,7 +51,7 @@ struct Bid { LoanDetails loanDetails; Terms terms; BidState state; - PaymentType paymentType; + PaymentType paymentType; // DEPRECATED } /** @@ -82,7 +82,7 @@ struct LoanDetails { */ struct Terms { uint256 paymentCycleAmount; - uint32 paymentCycle; + uint32 paymentCycle; // DEPRECATED uint16 APR; } @@ -90,31 +90,31 @@ abstract contract TellerV2Storage_G0 { /** Storage Variables */ // Current number of bids. - uint256 public bidId; + uint256 public nextBidId; // Mapping of bidId to bid information. mapping(uint256 => Bid) public bids; // Mapping of borrowers to borrower requests. - mapping(address => uint256[]) public borrowerBids; + mapping(address => uint256[]) public borrowerBids; //DEPRECATED // Mapping of volume filled by lenders. - mapping(address => uint256) public __lenderVolumeFilled; // DEPRECIATED + mapping(address => uint256) public __lenderVolumeFilled; // DEPRECATED // Volume filled by all lenders. - uint256 public __totalVolumeFilled; // DEPRECIATED + uint256 public __totalVolumeFilled; // DEPRECATED // List of allowed lending tokens EnumerableSet.AddressSet internal __lendingTokensSet; // DEPRECATED - IMarketRegistry public marketRegistry; + IMarketRegistry_V2 public marketRegistry; IReputationManager public reputationManager; // Mapping of borrowers to borrower requests. - mapping(address => EnumerableSet.UintSet) internal _borrowerBidsActive; + mapping(address => EnumerableSet.UintSet) internal _borrowerBidsActive; //DEPRECATED - mapping(uint256 => uint32) public bidDefaultDuration; - mapping(uint256 => uint32) public bidExpirationTime; + mapping(uint256 => uint32) public bidDefaultDuration; //DEPRECATED + mapping(uint256 => uint32) public bidExpirationTime; //DEPRECATED // Mapping of volume filled by lenders. // Asset address => Lender address => Volume amount @@ -128,7 +128,7 @@ abstract contract TellerV2Storage_G0 { // Mapping of metadataURIs by bidIds. // Bid Id => metadataURI string - mapping(uint256 => string) public uris; + mapping(uint256 => string) public uris; //DEPRECATED } abstract contract TellerV2Storage_G1 is TellerV2Storage_G0 { @@ -151,7 +151,7 @@ abstract contract TellerV2Storage_G4 is TellerV2Storage_G3 { // Address of the lender manager contract ILenderManager public lenderManager; // BidId to payment cycle type (custom or monthly) - mapping(uint256 => PaymentCycleType) public bidPaymentCycleType; + mapping(uint256 => PaymentCycleType) public bidPaymentCycleType; //DEPRECATED } abstract contract TellerV2Storage_G5 is TellerV2Storage_G4 { @@ -164,4 +164,10 @@ abstract contract TellerV2Storage_G6 is TellerV2Storage_G5 { mapping(uint256 => address) public collateralManagerForBid; //if this is zero, that means v1 } -abstract contract TellerV2Storage is TellerV2Storage_G6 {} +abstract contract TellerV2Storage_G7 is TellerV2Storage_G6 { + // If this is zero for a bid, the bid will use the values in the bid struct / bidDefaultDuration / bidExpirationTime + //need internal fns to do this if/then + mapping(uint256 => bytes32) public bidMarketTermsId; +} + +abstract contract TellerV2Storage is TellerV2Storage_G7 {} diff --git a/packages/contracts/contracts/interfaces/IMarketRegistry.sol b/packages/contracts/contracts/interfaces/IMarketRegistry.sol index 4dd6cf698..3afed3c35 100644 --- a/packages/contracts/contracts/interfaces/IMarketRegistry.sol +++ b/packages/contracts/contracts/interfaces/IMarketRegistry.sol @@ -1,28 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../EAS/TellerAS.sol"; import { PaymentType, PaymentCycleType } from "../libraries/V2Calculations.sol"; -interface IMarketRegistry { - function initialize(TellerAS tellerAs) external; - - function isVerifiedLender(uint256 _marketId, address _lender) - external - view - returns (bool, bytes32); +interface IMarketRegistry { function isMarketOpen(uint256 _marketId) external view returns (bool); function isMarketClosed(uint256 _marketId) external view returns (bool); - function isVerifiedBorrower(uint256 _marketId, address _borrower) - external - view - returns (bool, bytes32); - function getMarketOwner(uint256 _marketId) external view returns (address); + function closeMarket(uint256 _marketId) external; + function getMarketFeeRecipient(uint256 _marketId) external view @@ -33,10 +23,7 @@ interface IMarketRegistry { view returns (string memory); - function getPaymentCycle(uint256 _marketId) - external - view - returns (uint32, PaymentCycleType); + function getPaymentDefaultDuration(uint256 _marketId) external @@ -48,39 +35,26 @@ interface IMarketRegistry { view returns (uint32); + function getPaymentType(uint256 _marketId) + external + view + returns (PaymentType); + + function getMarketplaceFee(uint256 _marketId) external view returns (uint16); - function getPaymentType(uint256 _marketId) + function isVerifiedBorrower(uint256 _marketId, address _borrower) external view - returns (PaymentType); + returns (bool, bytes32); + + function isVerifiedLender(uint256 _marketId, address _lender) + external + view + returns (bool, bytes32); - function createMarket( - address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _requireLenderAttestation, - bool _requireBorrowerAttestation, - PaymentType _paymentType, - PaymentCycleType _paymentCycleType, - string calldata _uri - ) external returns (uint256 marketId_); - - function createMarket( - address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _requireLenderAttestation, - bool _requireBorrowerAttestation, - string calldata _uri - ) external returns (uint256 marketId_); - function closeMarket(uint256 _marketId) external; } diff --git a/packages/contracts/contracts/interfaces/IMarketRegistry_V1.sol b/packages/contracts/contracts/interfaces/IMarketRegistry_V1.sol new file mode 100644 index 000000000..e11dc4a91 --- /dev/null +++ b/packages/contracts/contracts/interfaces/IMarketRegistry_V1.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../EAS/TellerAS.sol"; +import { PaymentType, PaymentCycleType } from "../libraries/V2Calculations.sol"; + +import { IMarketRegistry } from "./IMarketRegistry.sol"; + +interface IMarketRegistry_V1 is IMarketRegistry { + function initialize(TellerAS tellerAs) external; + + + + function createMarket( + address _initialOwner, + uint32 _paymentCycleDuration, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + PaymentType _paymentType, + PaymentCycleType _paymentCycleType, + string calldata _uri + ) external returns (uint256 marketId_); + + function createMarket( + address _initialOwner, + uint32 _paymentCycleDuration, + uint32 _paymentDefaultDuration, + uint32 _bidExpirationTime, + uint16 _feePercent, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + string calldata _uri + ) external returns (uint256 marketId_); + + function getPaymentCycle(uint256 _marketId) + external + view + returns (uint32, PaymentCycleType); +} diff --git a/packages/contracts/contracts/interfaces/IMarketRegistry_V2.sol b/packages/contracts/contracts/interfaces/IMarketRegistry_V2.sol new file mode 100644 index 000000000..5a9476c78 --- /dev/null +++ b/packages/contracts/contracts/interfaces/IMarketRegistry_V2.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +import { PaymentType, PaymentCycleType } from "../libraries/V2Calculations.sol"; + +import { IMarketRegistry } from "./IMarketRegistry.sol"; + +interface IMarketRegistry_V2 is IMarketRegistry { + struct MarketplaceTerms { + uint16 marketplaceFeePercent; // 10000 is 100% + PaymentType paymentType; + PaymentCycleType paymentCycleType; + uint32 paymentCycleDuration; // unix time (seconds) + uint32 paymentDefaultDuration; //unix time + uint32 bidExpirationTime; //unix time + address feeRecipient; + } + + + function getMarketTermsForLending(bytes32 _marketTermsId) + external + view + returns (uint32, PaymentCycleType, PaymentType, uint32, uint32); + + function getMarketFeeTerms(bytes32 _marketTermsId) + external + view + returns (address, uint16); + + function getBidExpirationTimeForTerms(bytes32 _marketTermsId) + external + view + returns (uint32); + + function getPaymentDefaultDurationForTerms(bytes32 _marketTermsId) + external + view + returns (uint32); + + function getPaymentTypeForTerms(bytes32 _marketTermsId) + external + view + returns (PaymentType); + + function getPaymentCycleTypeForTerms(bytes32 _marketTermsId) + external + view + returns (PaymentCycleType); + + function getPaymentCycleDurationForTerms(bytes32 _marketTermsId) + external + view + returns (uint32); + + function getPaymentCycleType(uint256 _marketId) + external + view + returns (PaymentCycleType); + + function getPaymentCycleDuration(uint256 _marketId) + external + view + returns (uint32); + + function createMarket( + address _initialOwner, + bool _requireLenderAttestation, + bool _requireBorrowerAttestation, + string calldata _uri, + MarketplaceTerms memory _marketTermsParams + ) external returns (uint256 marketId_, bytes32 marketTerms_); + + + + function getCurrentTermsForMarket(uint256 _marketId) + external + view + returns (bytes32); +} diff --git a/packages/contracts/contracts/interfaces/IReputationManager.sol b/packages/contracts/contracts/interfaces/IReputationManager.sol index d0bacbd99..e413a8e54 100644 --- a/packages/contracts/contracts/interfaces/IReputationManager.sol +++ b/packages/contracts/contracts/interfaces/IReputationManager.sol @@ -26,7 +26,7 @@ interface IReputationManager { external returns (uint256[] memory); - function updateAccountReputation(address _account) external; + // function updateAccountReputation(address _account) external; function updateAccountReputation(address _account, uint256 _bidId) external diff --git a/packages/contracts/contracts/interfaces/ITellerV2.sol b/packages/contracts/contracts/interfaces/ITellerV2.sol index b74cce821..45b86c7bd 100644 --- a/packages/contracts/contracts/interfaces/ITellerV2.sol +++ b/packages/contracts/contracts/interfaces/ITellerV2.sol @@ -101,10 +101,12 @@ interface ITellerV2 { function getBidState(uint256 _bidId) external view returns (BidState); - function getBorrowerActiveLoanIds(address _borrower) + /* + function getBorrowerActiveLoanIds(address _borrower) external view returns (uint256[] memory); + */ /** * @notice Returns the borrower address for a given bid. diff --git a/packages/contracts/contracts/libraries/V2Calculations.sol b/packages/contracts/contracts/libraries/V2Calculations.sol index 0cf00d94c..4a01c3365 100644 --- a/packages/contracts/contracts/libraries/V2Calculations.sol +++ b/packages/contracts/contracts/libraries/V2Calculations.sol @@ -45,7 +45,8 @@ library V2Calculations { function calculateAmountOwed( Bid storage _bid, uint256 _timestamp, - PaymentCycleType _paymentCycleType + PaymentCycleType _paymentCycleType, + uint32 _paymentCycleDuration ) internal view @@ -61,7 +62,8 @@ library V2Calculations { _bid, lastRepaidTimestamp(_bid), _timestamp, - _paymentCycleType + _paymentCycleType, + _paymentCycleDuration ); } @@ -69,7 +71,8 @@ library V2Calculations { Bid storage _bid, uint256 _lastRepaidTimestamp, uint256 _timestamp, - PaymentCycleType _paymentCycleType + PaymentCycleType _paymentCycleType, + uint32 _paymentCycleDuration ) internal view @@ -94,9 +97,9 @@ library V2Calculations { bool isLastPaymentCycle; { uint256 lastPaymentCycleDuration = _bid.loanDetails.loanDuration % - _bid.terms.paymentCycle; + _paymentCycleDuration; if (lastPaymentCycleDuration == 0) { - lastPaymentCycleDuration = _bid.terms.paymentCycle; + lastPaymentCycleDuration = _paymentCycleDuration; } uint256 endDate = uint256(_bid.loanDetails.acceptedTimestamp) + @@ -121,7 +124,7 @@ library V2Calculations { uint256 owedAmount = isLastPaymentCycle ? owedPrincipal_ + interest_ : (_bid.terms.paymentCycleAmount * owedTime) / - _bid.terms.paymentCycle; + _paymentCycleDuration; duePrincipal_ = Math.min(owedAmount - interest_, owedPrincipal_); } diff --git a/packages/contracts/contracts/mock/MarketRegistryMock.sol b/packages/contracts/contracts/mock/MarketRegistryMock.sol index 2496a0b96..0023e29da 100644 --- a/packages/contracts/contracts/mock/MarketRegistryMock.sol +++ b/packages/contracts/contracts/mock/MarketRegistryMock.sol @@ -1,11 +1,11 @@ pragma solidity ^0.8.0; // SPDX-License-Identifier: MIT - import "../interfaces/IMarketRegistry.sol"; +import "../interfaces/IMarketRegistry_V2.sol"; import { PaymentType } from "../libraries/V2Calculations.sol"; -contract MarketRegistryMock is IMarketRegistry { +contract MarketRegistryMock is IMarketRegistry, IMarketRegistry_V2 { //address marketOwner; address public globalMarketOwner; @@ -15,83 +15,94 @@ contract MarketRegistryMock is IMarketRegistry { bool public globalBorrowerIsVerified = true; bool public globalLenderIsVerified = true; + bytes32 public globalTermsForMarket; + constructor() {} - function initialize(TellerAS _tellerAS) external {} + // function initialize(TellerAS _tellerAS) external {} - function isVerifiedLender(uint256 _marketId, address _lenderAddress) - public - view - returns (bool isVerified_, bytes32 uuid_) - { - isVerified_ = globalLenderIsVerified; + function getCurrentTermsForMarket( + uint256 _marketId + ) public view returns (bytes32) { + return globalTermsForMarket; + } + + function forceSetGlobalTermsForMarket(bytes32 _term) public { + globalTermsForMarket = _term; } function isMarketOpen(uint256 _marketId) public view returns (bool) { return !globalMarketsClosed; + } function isMarketClosed(uint256 _marketId) public view returns (bool) { return globalMarketsClosed; } - function isVerifiedBorrower(uint256 _marketId, address _borrower) - public - view - returns (bool isVerified_, bytes32 uuid_) - { + function isVerifiedBorrower( + uint256 _marketId, + address _borrower + ) public view returns (bool isVerified_, bytes32) { isVerified_ = globalBorrowerIsVerified; } - function getMarketOwner(uint256 _marketId) - public - view - override - returns (address) - { + function isVerifiedLender( + uint256 _marketId, + address _lenderAddress + ) public view returns (bool isVerified_, bytes32) { + isVerified_ = globalLenderIsVerified; + } + + function getMarketOwner( + uint256 _marketId + ) public view override returns (address) { return address(globalMarketOwner); } - function getMarketFeeRecipient(uint256 _marketId) - public - view - returns (address) - { + function getMarketFeeRecipient( + uint256 _marketId + ) public view returns (address) { return address(globalMarketFeeRecipient); } - function getMarketURI(uint256 _marketId) - public - view - returns (string memory) - { + function getMarketURI( + uint256 _marketId + ) public view returns (string memory) { return "url://"; } - function getPaymentCycle(uint256 _marketId) - public - view - returns (uint32, PaymentCycleType) - { - return (1000, PaymentCycleType.Seconds); + function getPaymentType( + uint256 _marketId + ) public view returns (PaymentType) { + return PaymentType.EMI; } - function getPaymentDefaultDuration(uint256 _marketId) - public - view - returns (uint32) - { + function getPaymentCycleDuration( + uint256 _marketId + ) public view returns (uint32) { return 1000; } - function getBidExpirationTime(uint256 _marketId) - public - view - returns (uint32) - { + function getPaymentCycleType( + uint256 _marketId + ) external view returns (PaymentCycleType) { + return PaymentCycleType.Seconds; + } + + function getPaymentDefaultDuration( + uint256 _marketId + ) public view returns (uint32) { return 1000; } + function getBidExpirationTime( + uint256 _marketId + ) public view returns (uint32) { + return 1000; + } + + //the current marketplace fee if a new loan is created NOT for existing loans in this market function getMarketplaceFee(uint256 _marketId) public view returns (uint16) { return 1000; } @@ -104,35 +115,59 @@ contract MarketRegistryMock is IMarketRegistry { globalMarketFeeRecipient = _feeRecipient; } - function getPaymentType(uint256 _marketId) + function getMarketFeeTerms( + bytes32 _marketTermsId + ) public view returns (address, uint16) { + return (address(this), 2000); + } + + function getMarketTermsForLending( + bytes32 _marketTermsId + ) public view - returns (PaymentType) - {} + returns (uint32, PaymentCycleType, PaymentType, uint32, uint32) + { + return (2000, PaymentCycleType.Seconds, PaymentType.EMI, 4000, 5000); + } - function createMarket( - address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, - bool _requireLenderAttestation, - bool _requireBorrowerAttestation, - PaymentType _paymentType, - PaymentCycleType _paymentCycleType, - string calldata _uri - ) public returns (uint256) {} + function getBidExpirationTimeForTerms( + bytes32 _marketTermsId + ) external view returns (uint32) { + return 4000; + } + + function getPaymentDefaultDurationForTerms( + bytes32 _marketTermsId + ) external view returns (uint32) { + return 6000; + } + + function getPaymentTypeForTerms( + bytes32 _marketTermsId + ) external view returns (PaymentType) { + return PaymentType.EMI; + } + + function getPaymentCycleTypeForTerms( + bytes32 _marketTermsId + ) external view returns (PaymentCycleType) { + return PaymentCycleType.Seconds; + } + + function getPaymentCycleDurationForTerms( + bytes32 _marketTermsId + ) external view returns (uint32) { + return 3000; + } function createMarket( address _initialOwner, - uint32 _paymentCycleDuration, - uint32 _paymentDefaultDuration, - uint32 _bidExpirationTime, - uint16 _feePercent, bool _requireLenderAttestation, bool _requireBorrowerAttestation, - string calldata _uri - ) public returns (uint256) {} + string calldata _uri, + MarketplaceTerms memory _marketTermsParams + ) external returns (uint256 marketId_, bytes32 marketTerms_) {} function closeMarket(uint256 _marketId) public {} diff --git a/packages/contracts/contracts/mock/TellerV2SolMock.sol b/packages/contracts/contracts/mock/TellerV2SolMock.sol index 1e18878c5..cbe14c58d 100644 --- a/packages/contracts/contracts/mock/TellerV2SolMock.sol +++ b/packages/contracts/contracts/mock/TellerV2SolMock.sol @@ -17,10 +17,13 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { address public trustedForwarder; address public approvedForwarder; + PaymentCycleType globalBidPaymentCycleType = PaymentCycleType.Seconds; + uint32 globalBidPaymentCycleDuration = 3000; + Bid mockBid; function setMarketRegistry(address _marketRegistry) public { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); } function getMarketRegistry() external view returns (IMarketRegistry) { @@ -40,9 +43,9 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { string calldata, address _receiver ) public returns (uint256 bidId_) { - bidId_ = bidId; + bidId_ = nextBidId; - Bid storage bid = bids[bidId]; + Bid storage bid = bids[bidId_]; bid.borrower = msg.sender; bid.receiver = _receiver != address(0) ? _receiver : bid.borrower; bid.marketplaceId = _marketId; @@ -51,12 +54,12 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { bid.loanDetails.loanDuration = _duration; bid.loanDetails.timestamp = uint32(block.timestamp); - (bid.terms.paymentCycle, bidPaymentCycleType[bidId]) = marketRegistry - .getPaymentCycle(_marketId); + /*(bid.terms.paymentCycle, bidPaymentCycleType[bidId]) = marketRegistry + .getPaymentCycle(_marketId);*/ bid.terms.APR = _APR; - bidId++; + nextBidId++; } function submitBid( @@ -89,7 +92,8 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { .calculateAmountOwed( bids[_bidId], block.timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); uint256 _amount = owedPrincipal + interest; @@ -115,41 +119,43 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { * @notice Calculates the minimum payment amount due for a loan. * @param _bidId The id of the loan bid to get the payment amount for. */ - function calculateAmountDue(uint256 _bidId, uint256 _timestamp) - public - view - returns (Payment memory due) - { + function calculateAmountDue( + uint256 _bidId, + uint256 _timestamp + ) public view returns (Payment memory due) { if (bids[_bidId].state != BidState.ACCEPTED) return due; (, uint256 duePrincipal, uint256 interest) = V2Calculations .calculateAmountOwed( bids[_bidId], _timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); due.principal = duePrincipal; due.interest = interest; } - function calculateAmountOwed(uint256 _bidId, uint256 _timestamp) - public - view - returns (Payment memory due) - { + function calculateAmountOwed( + uint256 _bidId, + uint256 _timestamp + ) public view returns (Payment memory due) { if (bids[_bidId].state != BidState.ACCEPTED) return due; (uint256 owedPrincipal, , uint256 interest) = V2Calculations .calculateAmountOwed( bids[_bidId], _timestamp, - bidPaymentCycleType[_bidId] + _getBidPaymentCycleType(_bidId), + _getBidPaymentCycleDuration(_bidId) ); due.principal = owedPrincipal; due.interest = interest; } - function lenderAcceptBid(uint256 _bidId) + function lenderAcceptBid( + uint256 _bidId + ) public returns ( uint256 amountToProtocol, @@ -174,12 +180,9 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { return (0, bid.loanDetails.principal, 0); } - function getBidState(uint256 _bidId) - public - view - virtual - returns (BidState) - { + function getBidState( + uint256 _bidId + ) public view virtual returns (BidState) { return bids[_bidId].state; } @@ -187,20 +190,15 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { collateralManagerMock = address(_collateralManager); } - function getCollateralManagerForBid(uint256 _bidId) - public - view - override - returns (ICollateralManager) - { + function getCollateralManagerForBid( + uint256 _bidId + ) public view override returns (ICollateralManager) { return _getCollateralManagerForBid(_bidId); } - function _getCollateralManagerForBid(uint256 _bidId) - internal - view - returns (ICollateralManager) - { + function _getCollateralManagerForBid( + uint256 _bidId + ) internal view returns (ICollateralManager) { return ICollateralManager(collateralManagerMock); } @@ -208,83 +206,67 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { bids[_bidId] = bid; } - function setTrustedMarketForwarder(uint256 _marketId, address _forwarder) - external - { + function setTrustedMarketForwarder( + uint256 _marketId, + address _forwarder + ) external { trustedForwarder = _forwarder; } - function approveMarketForwarder(uint256 _marketId, address _forwarder) - external - { + function approveMarketForwarder( + uint256 _marketId, + address _forwarder + ) external { approvedForwarder = _forwarder; } - function getLoanDetails(uint256 _bidId) - public - view - returns (LoanDetails memory) - { + function getLoanDetails( + uint256 _bidId + ) public view returns (LoanDetails memory) { return bids[_bidId].loanDetails; } - function getBorrowerActiveLoanIds(address _borrower) - public - view - returns (uint256[] memory) - {} + function getBorrowerActiveLoanIds( + address _borrower + ) public view returns (uint256[] memory) {} - function isLoanDefaulted(uint256 _bidId) - public - view - virtual - returns (bool) - {} + function isLoanDefaulted( + uint256 _bidId + ) public view virtual returns (bool) {} - function isLoanLiquidateable(uint256 _bidId) - public - view - virtual - returns (bool) - {} + function isLoanLiquidateable( + uint256 _bidId + ) public view virtual returns (bool) {} function isPaymentLate(uint256 _bidId) public view returns (bool) {} - function getLoanBorrower(uint256 _bidId) - external - view - virtual - returns (address borrower_) - { + function getLoanBorrower( + uint256 _bidId + ) external view virtual returns (address borrower_) { borrower_ = bids[_bidId].borrower; } - function getLoanLender(uint256 _bidId) - external - view - virtual - returns (address lender_) - { + function getLoanLender( + uint256 _bidId + ) external view virtual returns (address lender_) { lender_ = bids[_bidId].lender; } - function getLoanMarketId(uint256 _bidId) - external - view - returns (uint256 _marketId) - { + function getLoanMarketId( + uint256 _bidId + ) external view returns (uint256 _marketId) { _marketId = bids[_bidId].marketplaceId; } - function getLoanLendingToken(uint256 _bidId) - external - view - returns (address token_) - { + function getLoanLendingToken( + uint256 _bidId + ) external view returns (address token_) { token_ = address(bids[_bidId].loanDetails.lendingToken); } - function getLoanSummary(uint256 _bidId) + function getLoanSummary( + uint256 _bidId + ) external view returns ( @@ -314,6 +296,30 @@ contract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage { bids[_bidId].loanDetails.lastRepaidTimestamp = _timestamp; } + function _getBidPaymentCycleType( + uint256 _bidId + ) internal view returns (PaymentCycleType) { + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + if (bidTermsId != bytes32(0)) { + return marketRegistry.getPaymentCycleTypeForTerms(bidTermsId); + } + + return globalBidPaymentCycleType; + } + + function _getBidPaymentCycleDuration( + uint256 _bidId + ) internal view returns (uint32) { + bytes32 bidTermsId = bidMarketTermsId[_bidId]; + if (bidTermsId != bytes32(0)) { + return marketRegistry.getPaymentCycleDurationForTerms(bidTermsId); + } + + Bid storage bid = bids[_bidId]; + + return globalBidPaymentCycleDuration; + } + function collateralManager() external view returns (address) { return collateralManagerMock; } diff --git a/packages/contracts/deploy/upgrades/02_tellerv2_loan_liquidated_state copy.ts b/packages/contracts/deploy/upgrades/02_tellerv2_loan_liquidated_state.ts similarity index 100% rename from packages/contracts/deploy/upgrades/02_tellerv2_loan_liquidated_state copy.ts rename to packages/contracts/deploy/upgrades/02_tellerv2_loan_liquidated_state.ts diff --git a/packages/contracts/deploy/upgrades/04_tellerv2_collateral_manager_v2.ts b/packages/contracts/deploy/upgrades/04_tellerv2_collateral_manager_v2.ts index b2624fdd1..b22d3e6b1 100644 --- a/packages/contracts/deploy/upgrades/04_tellerv2_collateral_manager_v2.ts +++ b/packages/contracts/deploy/upgrades/04_tellerv2_collateral_manager_v2.ts @@ -60,7 +60,7 @@ deployFn.tags = [ 'teller-v2', 'teller-v2:collateral-manager-v2-upgrade' ] -deployFn.dependencies = ['teller-v2:deploy'] +deployFn.dependencies = ['teller-v2:deploy','collateral:manager-v2:deploy'] deployFn.skip = async (hre) => { return ( !hre.network.live || diff --git a/packages/contracts/deploy/upgrades/05_market_registry_v2.ts b/packages/contracts/deploy/upgrades/05_market_registry_v2.ts new file mode 100644 index 000000000..296f1e4cb --- /dev/null +++ b/packages/contracts/deploy/upgrades/05_market_registry_v2.ts @@ -0,0 +1,65 @@ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +const deployFn: DeployFunction = async (hre) => { + hre.log('----------') + hre.log('') + hre.log('MarketRegistryV2: Proposing upgrade...') + + //const tellerV2 = await hre.contracts.get('TellerV2') + //const trustedForwarder = await hre.contracts.get('MetaForwarder') + //const v2Calculations = await hre.deployments.get('V2Calculations') + + const marketRegistry = await hre.contracts.get('MarketRegistry') + + await hre.upgrades.proposeBatchTimelock({ + title: 'MarketRegistryV2: Upgrade for Market Registry V2', + description: ` +# MarketRegistryV2 + +* Modifies MarketRegistry so that it supports historical terms. +`, + _steps: [ + { + proxy: marketRegistry, + implFactory: await hre.ethers.getContractFactory('MarketRegistry' ), + + opts: { + unsafeAllow: [ + 'constructor', + 'state-variable-immutable', + 'external-library-linking' + ], + unsafeAllowRenames: true, + unsafeSkipStorageCheck:true, //caution ! + constructorArgs: [ ], + + + } + } + ] + }) + + hre.log('done.') + hre.log('') + hre.log('----------') + + return true +} + +// tags and deployment +deployFn.id = 'market-registry:v2-upgrade' +deployFn.tags = [ + 'proposal', + 'upgrade', + 'market-registry-v2-upgrade' +] +deployFn.dependencies = [ ] +deployFn.skip = async (hre) => { + return ( + !hre.network.live || + !['mainnet', 'polygon', 'arbitrum', 'goerli', 'sepolia'].includes( + hre.network.name + ) + ) +} +export default deployFn diff --git a/packages/contracts/deploy/upgrades/06_tellerv2_market_registry_v2.ts b/packages/contracts/deploy/upgrades/06_tellerv2_market_registry_v2.ts new file mode 100644 index 000000000..dbfd18a1e --- /dev/null +++ b/packages/contracts/deploy/upgrades/06_tellerv2_market_registry_v2.ts @@ -0,0 +1,69 @@ +import { DeployFunction } from 'hardhat-deploy/dist/types' + +const deployFn: DeployFunction = async (hre) => { + hre.log('----------') + hre.log('') + hre.log('TellerV2: Proposing upgrade...') + + const tellerV2 = await hre.contracts.get('TellerV2') + const trustedForwarder = await hre.contracts.get('MetaForwarder') + const v2Calculations = await hre.deployments.get('V2Calculations') + + //const marketRegistry = await hre.contracts.get('MarketRegistry') + + await hre.upgrades.proposeBatchTimelock({ + title: 'TellerV2: Upgrade for Market Registry V2', + description: ` +# TellerV2 + +* Modifies Teller V2 so that it supports the Market Registry V2. +`, + _steps: [ + { + proxy: tellerV2, + implFactory: await hre.ethers.getContractFactory('TellerV2', { + libraries: { + V2Calculations: v2Calculations.address + } + }), + + opts: { + unsafeAllow: [ + 'constructor', + 'state-variable-immutable', + 'external-library-linking' + ], + unsafeAllowRenames: true, + constructorArgs: [await trustedForwarder.getAddress()], + + + } + } + ] + }) + + hre.log('done.') + hre.log('') + hre.log('----------') + + return true +} + +// tags and deployment +deployFn.id = 'teller-v2:market-registry-v2-upgrade' +deployFn.tags = [ + 'proposal', + 'upgrade', + 'teller-v2', + 'teller-v2:market-registry-v2-upgrade' +] +deployFn.dependencies = ['teller-v2:deploy','market-registry:v2-upgrade'] +deployFn.skip = async (hre) => { + return ( + !hre.network.live || + !['mainnet', 'polygon', 'arbitrum', 'goerli', 'sepolia'].includes( + hre.network.name + ) + ) +} +export default deployFn diff --git a/packages/contracts/deployments/goerli/.migrations.json b/packages/contracts/deployments/goerli/.migrations.json index 753d57f7c..65a7710dd 100644 --- a/packages/contracts/deployments/goerli/.migrations.json +++ b/packages/contracts/deployments/goerli/.migrations.json @@ -23,5 +23,7 @@ "lender-commitment-forwarder:extensions:flash-rollover:deploy": 1698172718, "teller-v2:loan-liquidated-state-upgrade": 1698172870, "teller-v2:collateral-manager-v2-upgrade": 1698175349, - "lender-commitment-forwarder:extensions:flash-rollover:g3-upgrade": 1698175363 + "lender-commitment-forwarder:extensions:flash-rollover:g3-upgrade": 1698175363, + "teller-v2:market-registry-v2-upgrade": 1698243480, + "market-registry:v2-upgrade": 1698243681 } \ No newline at end of file diff --git a/packages/contracts/deployments/goerli/MarketRegistry.json b/packages/contracts/deployments/goerli/MarketRegistry.json index 4eab2e3a2..1c9fc2ba7 100644 --- a/packages/contracts/deployments/goerli/MarketRegistry.json +++ b/packages/contracts/deployments/goerli/MarketRegistry.json @@ -2,1538 +2,1463 @@ "address": "0x74FFC87282ab32c8E0969E26F93C820a213ae146", "abi": [ { - "inputs": [], - "name": "NotPayable", - "type": "error" - }, - { + "type": "event", "anonymous": false, + "name": "BorrowerAttestation", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "borrower", - "type": "address" + "indexed": false } - ], - "name": "BorrowerAttestation", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "BorrowerExitMarket", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "borrower", - "type": "address" + "indexed": false } - ], - "name": "BorrowerExitMarket", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "BorrowerRevocation", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "borrower", - "type": "address" + "indexed": false } - ], - "name": "BorrowerRevocation", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "DefineMarketTerms", "inputs": [ { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" + "type": "bytes32", + "name": "marketTermsId", + "indexed": false } - ], + ] + }, + { + "type": "event", + "anonymous": false, "name": "Initialized", - "type": "event" + "inputs": [ + { + "type": "uint8", + "name": "version", + "indexed": false + } + ] }, { + "type": "event", "anonymous": false, + "name": "LenderAttestation", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "lender", - "type": "address" + "indexed": false } - ], - "name": "LenderAttestation", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "LenderExitMarket", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "lender", - "type": "address" + "indexed": false } - ], - "name": "LenderExitMarket", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "LenderRevocation", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "lender", - "type": "address" + "indexed": false } - ], - "name": "LenderRevocation", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "MarketClosed", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false } - ], - "name": "MarketClosed", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "MarketCreated", "inputs": [ { - "indexed": true, - "internalType": "address", + "type": "address", "name": "owner", - "type": "address" + "indexed": true }, { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false } - ], - "name": "MarketCreated", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetBidExpirationTime", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "uint32", + "type": "uint32", "name": "duration", - "type": "uint32" + "indexed": false } - ], - "name": "SetBidExpirationTime", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetCurrentMarketTermsForMarket", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "bool", - "name": "required", - "type": "bool" + "type": "bytes32", + "name": "marketTermsId", + "indexed": false } - ], + ] + }, + { + "type": "event", + "anonymous": false, "name": "SetMarketBorrowerAttestation", - "type": "event" + "inputs": [ + { + "type": "uint256", + "name": "marketId", + "indexed": false + }, + { + "type": "bool", + "name": "required", + "indexed": false + } + ] }, { + "type": "event", "anonymous": false, + "name": "SetMarketFee", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "uint16", + "type": "uint16", "name": "feePct", - "type": "uint16" + "indexed": false } - ], - "name": "SetMarketFee", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetMarketFeeRecipient", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "newRecipient", - "type": "address" + "indexed": false } - ], - "name": "SetMarketFeeRecipient", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetMarketLenderAttestation", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "bool", + "type": "bool", "name": "required", - "type": "bool" + "indexed": false } - ], - "name": "SetMarketLenderAttestation", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetMarketOwner", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "address", + "type": "address", "name": "newOwner", - "type": "address" + "indexed": false } - ], - "name": "SetMarketOwner", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetMarketPaymentType", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "enum PaymentType", + "type": "uint8", "name": "paymentType", - "type": "uint8" + "indexed": false } - ], - "name": "SetMarketPaymentType", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetMarketURI", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "string", + "type": "string", "name": "uri", - "type": "string" + "indexed": false } - ], - "name": "SetMarketURI", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetPaymentCycle", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "enum PaymentCycleType", + "type": "uint8", "name": "paymentCycleType", - "type": "uint8" + "indexed": false }, { - "indexed": false, - "internalType": "uint32", + "type": "uint32", "name": "value", - "type": "uint32" + "indexed": false } - ], - "name": "SetPaymentCycle", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetPaymentCycleDuration", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "uint32", + "type": "uint32", "name": "duration", - "type": "uint32" + "indexed": false } - ], - "name": "SetPaymentCycleDuration", - "type": "event" + ] }, { + "type": "event", "anonymous": false, + "name": "SetPaymentDefaultDuration", "inputs": [ { - "indexed": false, - "internalType": "uint256", + "type": "uint256", "name": "marketId", - "type": "uint256" + "indexed": false }, { - "indexed": false, - "internalType": "uint32", + "type": "uint32", "name": "duration", - "type": "uint32" + "indexed": false } - ], - "name": "SetPaymentDefaultDuration", - "type": "event" + ] }, { - "inputs": [], + "type": "function", "name": "CURRENT_CODE_VERSION", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [], "outputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "type": "uint256", + "name": "" } - ], + ] + }, + { + "type": "function", + "name": "__lenderAttestationSchemaId", + "constant": true, "stateMutability": "view", - "type": "function" + "payable": false, + "inputs": [], + "outputs": [ + { + "type": "bytes32", + "name": "" + } + ] }, { + "type": "function", + "name": "_getMarketTermsHashId", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint32", + "name": "_paymentCycleDuration" }, { - "internalType": "address", - "name": "_borrowerAddress", - "type": "address" + "type": "uint8", + "name": "_newPaymentType" }, { - "internalType": "uint256", - "name": "_expirationTime", - "type": "uint256" + "type": "uint8", + "name": "_paymentCycleType" }, { - "internalType": "uint8", - "name": "_v", - "type": "uint8" + "type": "uint32", + "name": "_paymentDefaultDuration" }, { - "internalType": "bytes32", - "name": "_r", - "type": "bytes32" + "type": "uint32", + "name": "_bidExpirationTime" }, { - "internalType": "bytes32", - "name": "_s", - "type": "bytes32" - } - ], - "name": "attestBorrower", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint16", + "name": "_feePercent" }, { - "internalType": "address", - "name": "_borrowerAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_expirationTime", - "type": "uint256" + "type": "address", + "name": "_feeRecipient" } ], - "name": "attestBorrower", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "type": "bytes32", + "name": "" + } + ] }, { + "type": "function", + "name": "attestBorrower", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_lenderAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_expirationTime", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "_v", - "type": "uint8" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "bytes32", - "name": "_r", - "type": "bytes32" + "type": "address", + "name": "_borrowerAddress" }, { - "internalType": "bytes32", - "name": "_s", - "type": "bytes32" + "type": "uint256", + "name": "_expirationTime" } ], - "name": "attestLender", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "attestLender", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "address", - "name": "_lenderAddress", - "type": "address" + "type": "address", + "name": "_lenderAddress" }, { - "internalType": "uint256", - "name": "_expirationTime", - "type": "uint256" + "type": "uint256", + "name": "_expirationTime" } ], - "name": "attestLender", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { - "inputs": [], + "type": "function", "name": "borrowerAttestationSchemaId", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [], "outputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "type": "bytes32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "borrowerExitMarket", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "borrowerExitMarket", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "closeMarket", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "closeMarket", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "createMarket", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "address", - "name": "_initialOwner", - "type": "address" - }, - { - "internalType": "uint32", - "name": "_paymentCycleDuration", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "_paymentDefaultDuration", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "_bidExpirationTime", - "type": "uint32" - }, - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - }, - { - "internalType": "bool", - "name": "_requireLenderAttestation", - "type": "bool" - }, - { - "internalType": "bool", - "name": "_requireBorrowerAttestation", - "type": "bool" - }, + "type": "address", + "name": "_initialOwner" + }, + { + "type": "bool", + "name": "_requireLenderAttestation" + }, + { + "type": "bool", + "name": "_requireBorrowerAttestation" + }, + { + "type": "string", + "name": "_uri" + }, + { + "type": "tuple", + "name": "_marketTermsParams", + "components": [ + { + "type": "uint16", + "name": "marketplaceFeePercent" + }, + { + "type": "uint8", + "name": "paymentType" + }, + { + "type": "uint8", + "name": "paymentCycleType" + }, + { + "type": "uint32", + "name": "paymentCycleDuration" + }, + { + "type": "uint32", + "name": "paymentDefaultDuration" + }, + { + "type": "uint32", + "name": "bidExpirationTime" + }, + { + "type": "address", + "name": "feeRecipient" + } + ] + } + ], + "outputs": [ { - "internalType": "enum PaymentType", - "name": "_paymentType", - "type": "uint8" + "type": "uint256", + "name": "marketId_" }, { - "internalType": "enum PaymentCycleType", - "name": "_paymentCycleType", - "type": "uint8" - }, + "type": "bytes32", + "name": "marketTerms_" + } + ] + }, + { + "type": "function", + "name": "currentMarketTermsForMarket", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [ { - "internalType": "string", - "name": "_uri", - "type": "string" + "type": "uint256", + "name": "" } ], - "name": "createMarket", "outputs": [ { - "internalType": "uint256", - "name": "marketId_", - "type": "uint256" + "type": "bytes32", + "name": "" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "name": "getAllVerifiedBorrowersForMarket", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "address", - "name": "_initialOwner", - "type": "address" - }, - { - "internalType": "uint32", - "name": "_paymentCycleDuration", - "type": "uint32" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "uint32", - "name": "_paymentDefaultDuration", - "type": "uint32" + "type": "uint256", + "name": "_page" }, { - "internalType": "uint32", - "name": "_bidExpirationTime", - "type": "uint32" - }, - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - }, - { - "internalType": "bool", - "name": "_requireLenderAttestation", - "type": "bool" - }, - { - "internalType": "bool", - "name": "_requireBorrowerAttestation", - "type": "bool" - }, - { - "internalType": "string", - "name": "_uri", - "type": "string" + "type": "uint256", + "name": "_perPage" } ], - "name": "createMarket", "outputs": [ { - "internalType": "uint256", - "name": "marketId_", - "type": "uint256" + "type": "address[]", + "name": "" } - ], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "name": "getAllVerifiedLendersForMarket", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "uint256", - "name": "_page", - "type": "uint256" + "type": "uint256", + "name": "_page" }, { - "internalType": "uint256", - "name": "_perPage", - "type": "uint256" + "type": "uint256", + "name": "_perPage" } ], - "name": "getAllVerifiedBorrowersForMarket", "outputs": [ { - "internalType": "address[]", - "name": "", - "type": "address[]" + "type": "address[]", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getBidExpirationTime", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, + "type": "uint256", + "name": "_marketId" + } + ], + "outputs": [ { - "internalType": "uint256", - "name": "_page", - "type": "uint256" - }, + "type": "uint32", + "name": "" + } + ] + }, + { + "type": "function", + "name": "getBidExpirationTimeForTerms", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [ { - "internalType": "uint256", - "name": "_perPage", - "type": "uint256" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "getAllVerifiedLendersForMarket", "outputs": [ { - "internalType": "address[]", - "name": "", - "type": "address[]" + "type": "uint32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getCurrentTermsForMarket", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getBidExpirationTime", "outputs": [ { - "internalType": "uint32", - "name": "", - "type": "uint32" + "type": "bytes32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketAttestationRequirements", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getMarketAttestationRequirements", "outputs": [ { - "internalType": "bool", - "name": "lenderAttestationRequired", - "type": "bool" + "type": "bool", + "name": "lenderAttestationRequired" }, { - "internalType": "bool", - "name": "borrowerAttestationRequired", - "type": "bool" + "type": "bool", + "name": "borrowerAttestationRequired" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketData", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getMarketData", "outputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint32", - "name": "paymentCycleDuration", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "paymentDefaultDuration", - "type": "uint32" + "type": "address", + "name": "owner" }, { - "internalType": "uint32", - "name": "loanExpirationTime", - "type": "uint32" + "type": "string", + "name": "metadataURI" }, { - "internalType": "string", - "name": "metadataURI", - "type": "string" + "type": "bool", + "name": "borrowerAttestationRequired" }, { - "internalType": "uint16", - "name": "marketplaceFeePercent", - "type": "uint16" + "type": "bool", + "name": "lenderAttestationRequired" }, { - "internalType": "bool", - "name": "lenderAttestationRequired", - "type": "bool" + "type": "bytes32", + "name": "marketTermsId" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketFeeRecipient", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getMarketFeeRecipient", "outputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "type": "address", + "name": "_recipient" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketFeeTerms", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "getMarketOwner", "outputs": [ { - "internalType": "address", - "name": "", - "type": "address" + "type": "address", + "name": "" + }, + { + "type": "uint16", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketOwner", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getMarketURI", "outputs": [ { - "internalType": "string", - "name": "", - "type": "string" + "type": "address", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketTermsData", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "getMarketplaceFee", "outputs": [ { - "internalType": "uint16", - "name": "fee", - "type": "uint16" + "type": "uint32", + "name": "paymentCycleDuration" + }, + { + "type": "uint8", + "name": "paymentType" + }, + { + "type": "uint8", + "name": "paymentCycleType" + }, + { + "type": "uint32", + "name": "paymentDefaultDuration" + }, + { + "type": "uint32", + "name": "bidExpirationTime" + }, + { + "type": "uint16", + "name": "feePercent" + }, + { + "type": "address", + "name": "feeRecipient" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketTermsForLending", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "getPaymentCycle", "outputs": [ { - "internalType": "uint32", - "name": "", - "type": "uint32" + "type": "uint32", + "name": "" + }, + { + "type": "uint8", + "name": "" + }, + { + "type": "uint8", + "name": "" + }, + { + "type": "uint32", + "name": "" }, { - "internalType": "enum PaymentCycleType", - "name": "", - "type": "uint8" + "type": "uint32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketURI", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getPaymentDefaultDuration", "outputs": [ { - "internalType": "uint32", - "name": "", - "type": "uint32" + "type": "string", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getMarketplaceFee", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "getPaymentType", "outputs": [ { - "internalType": "enum PaymentType", - "name": "", - "type": "uint8" + "type": "uint16", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getPaymentCycleDuration", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "contract TellerAS", - "name": "_tellerAS", - "type": "address" + "type": "uint256", + "name": "_marketId" } ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "type": "uint32", + "name": "" + } + ] }, { + "type": "function", + "name": "getPaymentCycleDurationForTerms", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "isMarketClosed", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "type": "uint32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getPaymentCycleType", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" } ], - "name": "isMarketOpen", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "type": "uint8", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "isPayable", - "outputs": [ + "type": "function", + "name": "getPaymentCycleTypeForTerms", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "type": "bytes32", + "name": "_marketTermsId" } ], - "stateMutability": "pure", - "type": "function" + "outputs": [ + { + "type": "uint8", + "name": "" + } + ] }, { + "type": "function", + "name": "getPaymentDefaultDuration", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_borrowerAddress", - "type": "address" + "type": "uint256", + "name": "_marketId" } ], - "name": "isVerifiedBorrower", "outputs": [ { - "internalType": "bool", - "name": "isVerified_", - "type": "bool" - }, - { - "internalType": "bytes32", - "name": "uuid_", - "type": "bytes32" + "type": "uint32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { + "type": "function", + "name": "getPaymentDefaultDurationForTerms", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_lenderAddress", - "type": "address" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "isVerifiedLender", "outputs": [ { - "internalType": "bool", - "name": "isVerified_", - "type": "bool" - }, - { - "internalType": "bytes32", - "name": "uuid_", - "type": "bytes32" + "type": "uint32", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] }, { - "inputs": [], - "name": "lenderAttestationSchemaId", - "outputs": [ + "type": "function", + "name": "getPaymentType", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [ { - "internalType": "bytes32", - "name": "", - "type": "bytes32" + "type": "uint256", + "name": "_marketId" } ], - "stateMutability": "view", - "type": "function" + "outputs": [ + { + "type": "uint8", + "name": "" + } + ] }, { + "type": "function", + "name": "getPaymentTypeForTerms", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "bytes32", + "name": "_marketTermsId" } ], - "name": "lenderExitMarket", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "marketCount", "outputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "type": "uint8", + "name": "" } - ], - "stateMutability": "view", - "type": "function" + ] + }, + { + "type": "function", + "name": "initialize", + "constant": false, + "payable": false, + "inputs": [], + "outputs": [] }, { + "type": "function", + "name": "isMarketClosed", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "bytes", - "name": "schema", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "attestor", - "type": "address" + "type": "uint256", + "name": "_marketId" } ], - "name": "resolve", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "type": "bool", + "name": "" } - ], - "stateMutability": "payable", - "type": "function" + ] }, { + "type": "function", + "name": "isMarketOpen", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_borrowerAddress", - "type": "address" + "type": "uint256", + "name": "_marketId" } ], - "name": "revokeBorrower", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "type": "bool", + "name": "" + } + ] }, { + "type": "function", + "name": "isVerifiedBorrower", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "address", - "name": "_borrowerAddress", - "type": "address" - }, - { - "internalType": "uint8", - "name": "_v", - "type": "uint8" - }, + "type": "address", + "name": "_borrower" + } + ], + "outputs": [ { - "internalType": "bytes32", - "name": "_r", - "type": "bytes32" + "type": "bool", + "name": "isVerified_" }, { - "internalType": "bytes32", - "name": "_s", - "type": "bytes32" + "type": "bytes32", + "name": "uuid_" } - ], - "name": "revokeBorrower", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "name": "isVerifiedLender", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "address", - "name": "_lenderAddress", - "type": "address" - }, - { - "internalType": "uint8", - "name": "_v", - "type": "uint8" - }, + "type": "address", + "name": "_lender" + } + ], + "outputs": [ { - "internalType": "bytes32", - "name": "_r", - "type": "bytes32" + "type": "bool", + "name": "isVerified_" }, { - "internalType": "bytes32", - "name": "_s", - "type": "bytes32" + "type": "bytes32", + "name": "uuid_" } - ], - "name": "revokeLender", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "name": "lenderExitMarket", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_lenderAddress", - "type": "address" + "type": "uint256", + "name": "_marketId" } ], - "name": "revokeLender", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, + "type": "function", + "name": "marketCount", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [], + "outputs": [ { - "internalType": "uint32", - "name": "_duration", - "type": "uint32" + "type": "uint256", + "name": "" } - ], - "name": "setBidExpirationTime", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "name": "marketHasDefinedTerms", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "_required", - "type": "bool" + "type": "uint256", + "name": "_marketId" } ], - "name": "setBorrowerAttestationRequired", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "type": "bool", + "name": "" + } + ] }, { + "type": "function", + "name": "marketTerms", + "constant": true, + "stateMutability": "view", + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "_required", - "type": "bool" + "type": "bytes32", + "name": "" } ], - "name": "setLenderAttestationRequired", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "outputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint16", + "name": "marketplaceFeePercent" }, { - "internalType": "uint16", - "name": "_newPercent", - "type": "uint16" - } - ], - "name": "setMarketFeePercent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "type": "uint8", + "name": "paymentType" + }, + { + "type": "uint8", + "name": "paymentCycleType" + }, + { + "type": "uint32", + "name": "paymentCycleDuration" + }, + { + "type": "uint32", + "name": "paymentDefaultDuration" + }, { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint32", + "name": "bidExpirationTime" }, { - "internalType": "address", - "name": "_recipient", - "type": "address" + "type": "address", + "name": "feeRecipient" } - ], - "name": "setMarketFeeRecipient", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ] }, { + "type": "function", + "name": "revokeBorrower", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "enum PaymentType", - "name": "_newPaymentType", - "type": "uint8" + "type": "address", + "name": "_borrowerAddress" } ], - "name": "setMarketPaymentType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "revokeLender", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "string", - "name": "_uri", - "type": "string" + "type": "address", + "name": "_lenderAddress" } ], - "name": "setMarketURI", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "setBorrowerAttestationRequired", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "enum PaymentCycleType", - "name": "_paymentCycleType", - "type": "uint8" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "uint32", - "name": "_duration", - "type": "uint32" + "type": "bool", + "name": "_required" } ], - "name": "setPaymentCycle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "setLenderAttestationRequired", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "uint32", - "name": "_duration", - "type": "uint32" + "type": "bool", + "name": "_required" } ], - "name": "setPaymentDefaultDuration", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { - "inputs": [], - "name": "tellerAS", - "outputs": [ + "type": "function", + "name": "setMarketURI", + "constant": false, + "payable": false, + "inputs": [ + { + "type": "uint256", + "name": "_marketId" + }, { - "internalType": "contract TellerAS", - "name": "", - "type": "address" + "type": "string", + "name": "_uri" } ], - "stateMutability": "view", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "transferMarketOwnership", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" + "type": "uint256", + "name": "_marketId" }, { - "internalType": "address", - "name": "_newOwner", - "type": "address" + "type": "address", + "name": "_newOwner" } ], - "name": "transferMarketOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [] }, { + "type": "function", + "name": "updateMarketSettings", + "constant": false, + "payable": false, "inputs": [ { - "internalType": "uint256", - "name": "_marketId", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "_paymentCycleDuration", - "type": "uint32" - }, - { - "internalType": "enum PaymentType", - "name": "_newPaymentType", - "type": "uint8" - }, - { - "internalType": "enum PaymentCycleType", - "name": "_paymentCycleType", - "type": "uint8" - }, - { - "internalType": "uint32", - "name": "_paymentDefaultDuration", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "_bidExpirationTime", - "type": "uint32" - }, - { - "internalType": "uint16", - "name": "_feePercent", - "type": "uint16" - }, - { - "internalType": "bool", - "name": "_borrowerAttestationRequired", - "type": "bool" - }, - { - "internalType": "bool", - "name": "_lenderAttestationRequired", - "type": "bool" - }, - { - "internalType": "string", - "name": "_metadataURI", - "type": "string" + "type": "uint256", + "name": "_marketId" + }, + { + "type": "tuple", + "name": "_marketTermsParams", + "components": [ + { + "type": "uint16", + "name": "marketplaceFeePercent" + }, + { + "type": "uint8", + "name": "paymentType" + }, + { + "type": "uint8", + "name": "paymentCycleType" + }, + { + "type": "uint32", + "name": "paymentCycleDuration" + }, + { + "type": "uint32", + "name": "paymentDefaultDuration" + }, + { + "type": "uint32", + "name": "bidExpirationTime" + }, + { + "type": "address", + "name": "feeRecipient" + } + ] } ], - "name": "updateMarketSettings", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "outputs": [ + { + "type": "bytes32", + "name": "marketTermsId_" + } + ] }, { - "inputs": [], + "type": "function", "name": "version", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [], "outputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "type": "uint256", + "name": "" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" + ] } ], "transactionHash": "0xa483828107614708c307e656b8588a921c1eec5abe4ce361b199b582f5eef32d", @@ -1618,6 +1543,6 @@ "status": 1, "byzantium": true }, - "numDeployments": 4, + "numDeployments": 5, "implementation": "0xbC706F216B0E65329DaF7c43359E98eE197a3a58" } \ No newline at end of file diff --git a/packages/contracts/deployments/goerli/TellerV2.json b/packages/contracts/deployments/goerli/TellerV2.json index 174323757..99787ece4 100644 --- a/packages/contracts/deployments/goerli/TellerV2.json +++ b/packages/contracts/deployments/goerli/TellerV2.json @@ -266,6 +266,23 @@ } ] }, + { + "type": "event", + "anonymous": false, + "name": "SetBidMarketTerms", + "inputs": [ + { + "type": "uint256", + "name": "bidId", + "indexed": true + }, + { + "type": "bytes32", + "name": "marketTermsId", + "indexed": true + } + ] + }, { "type": "event", "anonymous": false, @@ -431,16 +448,21 @@ }, { "type": "function", - "name": "bidId", + "name": "bidMarketTermsId", "constant": true, "stateMutability": "view", "payable": false, - "inputs": [], - "outputs": [ + "inputs": [ { "type": "uint256", "name": "" } + ], + "outputs": [ + { + "type": "bytes32", + "name": "" + } ] }, { @@ -795,44 +817,6 @@ } ] }, - { - "type": "function", - "name": "getBorrowerActiveLoanIds", - "constant": true, - "stateMutability": "view", - "payable": false, - "inputs": [ - { - "type": "address", - "name": "_borrower" - } - ], - "outputs": [ - { - "type": "uint256[]", - "name": "" - } - ] - }, - { - "type": "function", - "name": "getBorrowerLoanIds", - "constant": true, - "stateMutability": "view", - "payable": false, - "inputs": [ - { - "type": "address", - "name": "_borrower" - } - ], - "outputs": [ - { - "type": "uint256[]", - "name": "" - } - ] - }, { "type": "function", "name": "getCollateralManagerForBid", @@ -1321,6 +1305,20 @@ } ] }, + { + "type": "function", + "name": "nextBidId", + "constant": true, + "stateMutability": "view", + "payable": false, + "inputs": [], + "outputs": [ + { + "type": "uint256", + "name": "" + } + ] + }, { "type": "function", "name": "owner", @@ -1748,6 +1746,6 @@ "status": 1, "byzantium": true }, - "numDeployments": 8, + "numDeployments": 9, "implementation": "0xFe5394B67196EA95301D6ECB5389E98A02984cC2" } \ No newline at end of file diff --git a/packages/contracts/deployments/goerli/V2Calculations.json b/packages/contracts/deployments/goerli/V2Calculations.json index cdd6f4949..bf96bcacd 100644 --- a/packages/contracts/deployments/goerli/V2Calculations.json +++ b/packages/contracts/deployments/goerli/V2Calculations.json @@ -1,5 +1,5 @@ { - "address": "0x81aeE453952D9ECcBFEc973EA65F2AACB0ee8E01", + "address": "0xeD639091f9fe621C79eBaA21Df5A4E86a960E485", "abi": [ { "inputs": [ @@ -41,28 +41,28 @@ "type": "function" } ], - "transactionHash": "0x5e9c9e43ce9a1a1fb79185bf22d2adf2c87d701b8b5a53b6205afa7f9b106c95", + "transactionHash": "0xe885840496f74e1bba7f642505aa1468a89a27876a2423d38789e91f1234a0e0", "receipt": { "to": null, "from": "0x5a5B978142C8F08Dd013901b50892baC49f3b700", - "contractAddress": "0x81aeE453952D9ECcBFEc973EA65F2AACB0ee8E01", + "contractAddress": "0xeD639091f9fe621C79eBaA21Df5A4E86a960E485", "transactionIndex": 0, "gasUsed": "598627", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x013a97c8996762fcac766e280abdb8da65503d49f6593e2b3e8fdef63028d8e4", - "transactionHash": "0x5e9c9e43ce9a1a1fb79185bf22d2adf2c87d701b8b5a53b6205afa7f9b106c95", + "blockHash": "0x3cabaf03b1979e32b62ca3f9427557b4d1980ba10a3ca6f44f8c1db763cb5138", + "transactionHash": "0xe885840496f74e1bba7f642505aa1468a89a27876a2423d38789e91f1234a0e0", "logs": [], - "blockNumber": 9924308, + "blockNumber": 9928898, "cumulativeGasUsed": "598627", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 2, - "solcInputHash": "580cfed7c4ff2e7046b618c158693001", - "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_acceptedTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_paymentCycle\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_loanDuration\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_lastRepaidTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"enum PaymentCycleType\",\"name\":\"_bidPaymentCycleType\",\"type\":\"PaymentCycleType\"}],\"name\":\"calculateNextDueDate\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"dueDate_\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/V2Calculations.sol\":\"V2Calculations\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165Upgradeable.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721Upgradeable is IERC165Upgradeable {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x2c0b89cef83f353c6f9488c013d8a5968587ffdd6dfc26aad53774214b97e229\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165Upgradeable {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xc6cef87559d0aeffdf0a99803de655938a7779ec0a3cd5d4383483ad85565a09\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint248 from uint256, reverting on\\n * overflow (when the input is greater than largest uint248).\\n *\\n * Counterpart to Solidity's `uint248` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 248 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint248(uint256 value) internal pure returns (uint248) {\\n require(value <= type(uint248).max, \\\"SafeCast: value doesn't fit in 248 bits\\\");\\n return uint248(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint240 from uint256, reverting on\\n * overflow (when the input is greater than largest uint240).\\n *\\n * Counterpart to Solidity's `uint240` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 240 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint240(uint256 value) internal pure returns (uint240) {\\n require(value <= type(uint240).max, \\\"SafeCast: value doesn't fit in 240 bits\\\");\\n return uint240(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint232 from uint256, reverting on\\n * overflow (when the input is greater than largest uint232).\\n *\\n * Counterpart to Solidity's `uint232` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 232 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint232(uint256 value) internal pure returns (uint232) {\\n require(value <= type(uint232).max, \\\"SafeCast: value doesn't fit in 232 bits\\\");\\n return uint232(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n *\\n * _Available since v4.2._\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint216 from uint256, reverting on\\n * overflow (when the input is greater than largest uint216).\\n *\\n * Counterpart to Solidity's `uint216` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 216 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint216(uint256 value) internal pure returns (uint216) {\\n require(value <= type(uint216).max, \\\"SafeCast: value doesn't fit in 216 bits\\\");\\n return uint216(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint208 from uint256, reverting on\\n * overflow (when the input is greater than largest uint208).\\n *\\n * Counterpart to Solidity's `uint208` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 208 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint208(uint256 value) internal pure returns (uint208) {\\n require(value <= type(uint208).max, \\\"SafeCast: value doesn't fit in 208 bits\\\");\\n return uint208(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint200 from uint256, reverting on\\n * overflow (when the input is greater than largest uint200).\\n *\\n * Counterpart to Solidity's `uint200` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 200 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint200(uint256 value) internal pure returns (uint200) {\\n require(value <= type(uint200).max, \\\"SafeCast: value doesn't fit in 200 bits\\\");\\n return uint200(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint192 from uint256, reverting on\\n * overflow (when the input is greater than largest uint192).\\n *\\n * Counterpart to Solidity's `uint192` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 192 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint192(uint256 value) internal pure returns (uint192) {\\n require(value <= type(uint192).max, \\\"SafeCast: value doesn't fit in 192 bits\\\");\\n return uint192(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint184 from uint256, reverting on\\n * overflow (when the input is greater than largest uint184).\\n *\\n * Counterpart to Solidity's `uint184` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 184 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint184(uint256 value) internal pure returns (uint184) {\\n require(value <= type(uint184).max, \\\"SafeCast: value doesn't fit in 184 bits\\\");\\n return uint184(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint176 from uint256, reverting on\\n * overflow (when the input is greater than largest uint176).\\n *\\n * Counterpart to Solidity's `uint176` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 176 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint176(uint256 value) internal pure returns (uint176) {\\n require(value <= type(uint176).max, \\\"SafeCast: value doesn't fit in 176 bits\\\");\\n return uint176(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint168 from uint256, reverting on\\n * overflow (when the input is greater than largest uint168).\\n *\\n * Counterpart to Solidity's `uint168` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 168 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint168(uint256 value) internal pure returns (uint168) {\\n require(value <= type(uint168).max, \\\"SafeCast: value doesn't fit in 168 bits\\\");\\n return uint168(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint160 from uint256, reverting on\\n * overflow (when the input is greater than largest uint160).\\n *\\n * Counterpart to Solidity's `uint160` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 160 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint160(uint256 value) internal pure returns (uint160) {\\n require(value <= type(uint160).max, \\\"SafeCast: value doesn't fit in 160 bits\\\");\\n return uint160(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint152 from uint256, reverting on\\n * overflow (when the input is greater than largest uint152).\\n *\\n * Counterpart to Solidity's `uint152` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 152 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint152(uint256 value) internal pure returns (uint152) {\\n require(value <= type(uint152).max, \\\"SafeCast: value doesn't fit in 152 bits\\\");\\n return uint152(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint144 from uint256, reverting on\\n * overflow (when the input is greater than largest uint144).\\n *\\n * Counterpart to Solidity's `uint144` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 144 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint144(uint256 value) internal pure returns (uint144) {\\n require(value <= type(uint144).max, \\\"SafeCast: value doesn't fit in 144 bits\\\");\\n return uint144(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint136 from uint256, reverting on\\n * overflow (when the input is greater than largest uint136).\\n *\\n * Counterpart to Solidity's `uint136` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 136 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint136(uint256 value) internal pure returns (uint136) {\\n require(value <= type(uint136).max, \\\"SafeCast: value doesn't fit in 136 bits\\\");\\n return uint136(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint120 from uint256, reverting on\\n * overflow (when the input is greater than largest uint120).\\n *\\n * Counterpart to Solidity's `uint120` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 120 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint120(uint256 value) internal pure returns (uint120) {\\n require(value <= type(uint120).max, \\\"SafeCast: value doesn't fit in 120 bits\\\");\\n return uint120(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint112 from uint256, reverting on\\n * overflow (when the input is greater than largest uint112).\\n *\\n * Counterpart to Solidity's `uint112` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 112 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint112(uint256 value) internal pure returns (uint112) {\\n require(value <= type(uint112).max, \\\"SafeCast: value doesn't fit in 112 bits\\\");\\n return uint112(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint104 from uint256, reverting on\\n * overflow (when the input is greater than largest uint104).\\n *\\n * Counterpart to Solidity's `uint104` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 104 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint104(uint256 value) internal pure returns (uint104) {\\n require(value <= type(uint104).max, \\\"SafeCast: value doesn't fit in 104 bits\\\");\\n return uint104(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n *\\n * _Available since v4.2._\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint88 from uint256, reverting on\\n * overflow (when the input is greater than largest uint88).\\n *\\n * Counterpart to Solidity's `uint88` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 88 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint88(uint256 value) internal pure returns (uint88) {\\n require(value <= type(uint88).max, \\\"SafeCast: value doesn't fit in 88 bits\\\");\\n return uint88(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint80 from uint256, reverting on\\n * overflow (when the input is greater than largest uint80).\\n *\\n * Counterpart to Solidity's `uint80` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 80 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint80(uint256 value) internal pure returns (uint80) {\\n require(value <= type(uint80).max, \\\"SafeCast: value doesn't fit in 80 bits\\\");\\n return uint80(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint72 from uint256, reverting on\\n * overflow (when the input is greater than largest uint72).\\n *\\n * Counterpart to Solidity's `uint72` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 72 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint72(uint256 value) internal pure returns (uint72) {\\n require(value <= type(uint72).max, \\\"SafeCast: value doesn't fit in 72 bits\\\");\\n return uint72(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint56 from uint256, reverting on\\n * overflow (when the input is greater than largest uint56).\\n *\\n * Counterpart to Solidity's `uint56` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 56 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint56(uint256 value) internal pure returns (uint56) {\\n require(value <= type(uint56).max, \\\"SafeCast: value doesn't fit in 56 bits\\\");\\n return uint56(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint48 from uint256, reverting on\\n * overflow (when the input is greater than largest uint48).\\n *\\n * Counterpart to Solidity's `uint48` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 48 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint48(uint256 value) internal pure returns (uint48) {\\n require(value <= type(uint48).max, \\\"SafeCast: value doesn't fit in 48 bits\\\");\\n return uint48(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint40 from uint256, reverting on\\n * overflow (when the input is greater than largest uint40).\\n *\\n * Counterpart to Solidity's `uint40` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 40 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint40(uint256 value) internal pure returns (uint40) {\\n require(value <= type(uint40).max, \\\"SafeCast: value doesn't fit in 40 bits\\\");\\n return uint40(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint24 from uint256, reverting on\\n * overflow (when the input is greater than largest uint24).\\n *\\n * Counterpart to Solidity's `uint24` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 24 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint24(uint256 value) internal pure returns (uint24) {\\n require(value <= type(uint24).max, \\\"SafeCast: value doesn't fit in 24 bits\\\");\\n return uint24(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n *\\n * _Available since v3.0._\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int248 from int256, reverting on\\n * overflow (when the input is less than smallest int248 or\\n * greater than largest int248).\\n *\\n * Counterpart to Solidity's `int248` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 248 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\\n downcasted = int248(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 248 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int240 from int256, reverting on\\n * overflow (when the input is less than smallest int240 or\\n * greater than largest int240).\\n *\\n * Counterpart to Solidity's `int240` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 240 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\\n downcasted = int240(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 240 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int232 from int256, reverting on\\n * overflow (when the input is less than smallest int232 or\\n * greater than largest int232).\\n *\\n * Counterpart to Solidity's `int232` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 232 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\\n downcasted = int232(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 232 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int224 from int256, reverting on\\n * overflow (when the input is less than smallest int224 or\\n * greater than largest int224).\\n *\\n * Counterpart to Solidity's `int224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\\n downcasted = int224(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int216 from int256, reverting on\\n * overflow (when the input is less than smallest int216 or\\n * greater than largest int216).\\n *\\n * Counterpart to Solidity's `int216` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 216 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\\n downcasted = int216(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 216 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int208 from int256, reverting on\\n * overflow (when the input is less than smallest int208 or\\n * greater than largest int208).\\n *\\n * Counterpart to Solidity's `int208` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 208 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\\n downcasted = int208(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 208 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int200 from int256, reverting on\\n * overflow (when the input is less than smallest int200 or\\n * greater than largest int200).\\n *\\n * Counterpart to Solidity's `int200` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 200 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\\n downcasted = int200(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 200 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int192 from int256, reverting on\\n * overflow (when the input is less than smallest int192 or\\n * greater than largest int192).\\n *\\n * Counterpart to Solidity's `int192` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 192 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\\n downcasted = int192(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 192 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int184 from int256, reverting on\\n * overflow (when the input is less than smallest int184 or\\n * greater than largest int184).\\n *\\n * Counterpart to Solidity's `int184` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 184 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\\n downcasted = int184(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 184 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int176 from int256, reverting on\\n * overflow (when the input is less than smallest int176 or\\n * greater than largest int176).\\n *\\n * Counterpart to Solidity's `int176` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 176 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\\n downcasted = int176(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 176 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int168 from int256, reverting on\\n * overflow (when the input is less than smallest int168 or\\n * greater than largest int168).\\n *\\n * Counterpart to Solidity's `int168` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 168 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\\n downcasted = int168(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 168 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int160 from int256, reverting on\\n * overflow (when the input is less than smallest int160 or\\n * greater than largest int160).\\n *\\n * Counterpart to Solidity's `int160` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 160 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\\n downcasted = int160(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 160 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int152 from int256, reverting on\\n * overflow (when the input is less than smallest int152 or\\n * greater than largest int152).\\n *\\n * Counterpart to Solidity's `int152` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 152 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\\n downcasted = int152(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 152 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int144 from int256, reverting on\\n * overflow (when the input is less than smallest int144 or\\n * greater than largest int144).\\n *\\n * Counterpart to Solidity's `int144` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 144 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\\n downcasted = int144(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 144 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int136 from int256, reverting on\\n * overflow (when the input is less than smallest int136 or\\n * greater than largest int136).\\n *\\n * Counterpart to Solidity's `int136` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 136 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\\n downcasted = int136(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 136 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\\n downcasted = int128(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int120 from int256, reverting on\\n * overflow (when the input is less than smallest int120 or\\n * greater than largest int120).\\n *\\n * Counterpart to Solidity's `int120` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 120 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\\n downcasted = int120(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 120 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int112 from int256, reverting on\\n * overflow (when the input is less than smallest int112 or\\n * greater than largest int112).\\n *\\n * Counterpart to Solidity's `int112` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 112 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\\n downcasted = int112(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 112 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int104 from int256, reverting on\\n * overflow (when the input is less than smallest int104 or\\n * greater than largest int104).\\n *\\n * Counterpart to Solidity's `int104` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 104 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\\n downcasted = int104(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 104 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int96 from int256, reverting on\\n * overflow (when the input is less than smallest int96 or\\n * greater than largest int96).\\n *\\n * Counterpart to Solidity's `int96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\\n downcasted = int96(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int88 from int256, reverting on\\n * overflow (when the input is less than smallest int88 or\\n * greater than largest int88).\\n *\\n * Counterpart to Solidity's `int88` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 88 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\\n downcasted = int88(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 88 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int80 from int256, reverting on\\n * overflow (when the input is less than smallest int80 or\\n * greater than largest int80).\\n *\\n * Counterpart to Solidity's `int80` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 80 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\\n downcasted = int80(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 80 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int72 from int256, reverting on\\n * overflow (when the input is less than smallest int72 or\\n * greater than largest int72).\\n *\\n * Counterpart to Solidity's `int72` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 72 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\\n downcasted = int72(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 72 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\\n downcasted = int64(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int56 from int256, reverting on\\n * overflow (when the input is less than smallest int56 or\\n * greater than largest int56).\\n *\\n * Counterpart to Solidity's `int56` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 56 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\\n downcasted = int56(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 56 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int48 from int256, reverting on\\n * overflow (when the input is less than smallest int48 or\\n * greater than largest int48).\\n *\\n * Counterpart to Solidity's `int48` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 48 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\\n downcasted = int48(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 48 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int40 from int256, reverting on\\n * overflow (when the input is less than smallest int40 or\\n * greater than largest int40).\\n *\\n * Counterpart to Solidity's `int40` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 40 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\\n downcasted = int40(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 40 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\\n downcasted = int32(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int24 from int256, reverting on\\n * overflow (when the input is less than smallest int24 or\\n * greater than largest int24).\\n *\\n * Counterpart to Solidity's `int24` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 24 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\\n downcasted = int24(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 24 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\\n downcasted = int16(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\\n downcasted = int8(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n *\\n * _Available since v3.0._\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x52a8cfb0f5239d11b457dcdd1b326992ef672714ca8da71a157255bddd13f3ad\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/EAS/TellerAS.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n// SPDX-License-Identifier: MIT\\n\\nimport \\\"../Types.sol\\\";\\nimport \\\"../interfaces/IEAS.sol\\\";\\nimport \\\"../interfaces/IASRegistry.sol\\\";\\n\\n/**\\n * @title TellerAS - Teller Attestation Service - based on EAS - Ethereum Attestation Service\\n */\\ncontract TellerAS is IEAS {\\n error AccessDenied();\\n error AlreadyRevoked();\\n error InvalidAttestation();\\n error InvalidExpirationTime();\\n error InvalidOffset();\\n error InvalidRegistry();\\n error InvalidSchema();\\n error InvalidVerifier();\\n error NotFound();\\n error NotPayable();\\n\\n string public constant VERSION = \\\"0.8\\\";\\n\\n // A terminator used when concatenating and hashing multiple fields.\\n string private constant HASH_TERMINATOR = \\\"@\\\";\\n\\n // The AS global registry.\\n IASRegistry private immutable _asRegistry;\\n\\n // The EIP712 verifier used to verify signed attestations.\\n IEASEIP712Verifier private immutable _eip712Verifier;\\n\\n // A mapping between attestations and their related attestations.\\n mapping(bytes32 => bytes32[]) private _relatedAttestations;\\n\\n // A mapping between an account and its received attestations.\\n mapping(address => mapping(bytes32 => bytes32[]))\\n private _receivedAttestations;\\n\\n // A mapping between an account and its sent attestations.\\n mapping(address => mapping(bytes32 => bytes32[])) private _sentAttestations;\\n\\n // A mapping between a schema and its attestations.\\n mapping(bytes32 => bytes32[]) private _schemaAttestations;\\n\\n // The global mapping between attestations and their UUIDs.\\n mapping(bytes32 => Attestation) private _db;\\n\\n // The global counter for the total number of attestations.\\n uint256 private _attestationsCount;\\n\\n bytes32 private _lastUUID;\\n\\n /**\\n * @dev Creates a new EAS instance.\\n *\\n * @param registry The address of the global AS registry.\\n * @param verifier The address of the EIP712 verifier.\\n */\\n constructor(IASRegistry registry, IEASEIP712Verifier verifier) {\\n if (address(registry) == address(0x0)) {\\n revert InvalidRegistry();\\n }\\n\\n if (address(verifier) == address(0x0)) {\\n revert InvalidVerifier();\\n }\\n\\n _asRegistry = registry;\\n _eip712Verifier = verifier;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getASRegistry() external view override returns (IASRegistry) {\\n return _asRegistry;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getEIP712Verifier()\\n external\\n view\\n override\\n returns (IEASEIP712Verifier)\\n {\\n return _eip712Verifier;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getAttestationsCount() external view override returns (uint256) {\\n return _attestationsCount;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function attest(\\n address recipient,\\n bytes32 schema,\\n uint256 expirationTime,\\n bytes32 refUUID,\\n bytes calldata data\\n ) public payable virtual override returns (bytes32) {\\n return\\n _attest(\\n recipient,\\n schema,\\n expirationTime,\\n refUUID,\\n data,\\n msg.sender\\n );\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function attestByDelegation(\\n address recipient,\\n bytes32 schema,\\n uint256 expirationTime,\\n bytes32 refUUID,\\n bytes calldata data,\\n address attester,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public payable virtual override returns (bytes32) {\\n _eip712Verifier.attest(\\n recipient,\\n schema,\\n expirationTime,\\n refUUID,\\n data,\\n attester,\\n v,\\n r,\\n s\\n );\\n\\n return\\n _attest(recipient, schema, expirationTime, refUUID, data, attester);\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function revoke(bytes32 uuid) public virtual override {\\n return _revoke(uuid, msg.sender);\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function revokeByDelegation(\\n bytes32 uuid,\\n address attester,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual override {\\n _eip712Verifier.revoke(uuid, attester, v, r, s);\\n\\n _revoke(uuid, attester);\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getAttestation(bytes32 uuid)\\n external\\n view\\n override\\n returns (Attestation memory)\\n {\\n return _db[uuid];\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function isAttestationValid(bytes32 uuid)\\n public\\n view\\n override\\n returns (bool)\\n {\\n return _db[uuid].uuid != 0;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function isAttestationActive(bytes32 uuid)\\n public\\n view\\n virtual\\n override\\n returns (bool)\\n {\\n return\\n isAttestationValid(uuid) &&\\n _db[uuid].expirationTime >= block.timestamp &&\\n _db[uuid].revocationTime == 0;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getReceivedAttestationUUIDs(\\n address recipient,\\n bytes32 schema,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view override returns (bytes32[] memory) {\\n return\\n _sliceUUIDs(\\n _receivedAttestations[recipient][schema],\\n start,\\n length,\\n reverseOrder\\n );\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getReceivedAttestationUUIDsCount(address recipient, bytes32 schema)\\n external\\n view\\n override\\n returns (uint256)\\n {\\n return _receivedAttestations[recipient][schema].length;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getSentAttestationUUIDs(\\n address attester,\\n bytes32 schema,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view override returns (bytes32[] memory) {\\n return\\n _sliceUUIDs(\\n _sentAttestations[attester][schema],\\n start,\\n length,\\n reverseOrder\\n );\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getSentAttestationUUIDsCount(address recipient, bytes32 schema)\\n external\\n view\\n override\\n returns (uint256)\\n {\\n return _sentAttestations[recipient][schema].length;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getRelatedAttestationUUIDs(\\n bytes32 uuid,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view override returns (bytes32[] memory) {\\n return\\n _sliceUUIDs(\\n _relatedAttestations[uuid],\\n start,\\n length,\\n reverseOrder\\n );\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getRelatedAttestationUUIDsCount(bytes32 uuid)\\n external\\n view\\n override\\n returns (uint256)\\n {\\n return _relatedAttestations[uuid].length;\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getSchemaAttestationUUIDs(\\n bytes32 schema,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view override returns (bytes32[] memory) {\\n return\\n _sliceUUIDs(\\n _schemaAttestations[schema],\\n start,\\n length,\\n reverseOrder\\n );\\n }\\n\\n /**\\n * @inheritdoc IEAS\\n */\\n function getSchemaAttestationUUIDsCount(bytes32 schema)\\n external\\n view\\n override\\n returns (uint256)\\n {\\n return _schemaAttestations[schema].length;\\n }\\n\\n /**\\n * @dev Attests to a specific AS.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n * @param expirationTime The expiration time of the attestation.\\n * @param refUUID An optional related attestation's UUID.\\n * @param data Additional custom data.\\n * @param attester The attesting account.\\n *\\n * @return The UUID of the new attestation.\\n */\\n function _attest(\\n address recipient,\\n bytes32 schema,\\n uint256 expirationTime,\\n bytes32 refUUID,\\n bytes calldata data,\\n address attester\\n ) private returns (bytes32) {\\n if (expirationTime <= block.timestamp) {\\n revert InvalidExpirationTime();\\n }\\n\\n IASRegistry.ASRecord memory asRecord = _asRegistry.getAS(schema);\\n if (asRecord.uuid == EMPTY_UUID) {\\n revert InvalidSchema();\\n }\\n\\n IASResolver resolver = asRecord.resolver;\\n if (address(resolver) != address(0x0)) {\\n if (msg.value != 0 && !resolver.isPayable()) {\\n revert NotPayable();\\n }\\n\\n if (\\n !resolver.resolve{ value: msg.value }(\\n recipient,\\n asRecord.schema,\\n data,\\n expirationTime,\\n attester\\n )\\n ) {\\n revert InvalidAttestation();\\n }\\n }\\n\\n Attestation memory attestation = Attestation({\\n uuid: EMPTY_UUID,\\n schema: schema,\\n recipient: recipient,\\n attester: attester,\\n time: block.timestamp,\\n expirationTime: expirationTime,\\n revocationTime: 0,\\n refUUID: refUUID,\\n data: data\\n });\\n\\n _lastUUID = _getUUID(attestation);\\n attestation.uuid = _lastUUID;\\n\\n _receivedAttestations[recipient][schema].push(_lastUUID);\\n _sentAttestations[attester][schema].push(_lastUUID);\\n _schemaAttestations[schema].push(_lastUUID);\\n\\n _db[_lastUUID] = attestation;\\n _attestationsCount++;\\n\\n if (refUUID != 0) {\\n if (!isAttestationValid(refUUID)) {\\n revert NotFound();\\n }\\n\\n _relatedAttestations[refUUID].push(_lastUUID);\\n }\\n\\n emit Attested(recipient, attester, _lastUUID, schema);\\n\\n return _lastUUID;\\n }\\n\\n function getLastUUID() external view returns (bytes32) {\\n return _lastUUID;\\n }\\n\\n /**\\n * @dev Revokes an existing attestation to a specific AS.\\n *\\n * @param uuid The UUID of the attestation to revoke.\\n * @param attester The attesting account.\\n */\\n function _revoke(bytes32 uuid, address attester) private {\\n Attestation storage attestation = _db[uuid];\\n if (attestation.uuid == EMPTY_UUID) {\\n revert NotFound();\\n }\\n\\n if (attestation.attester != attester) {\\n revert AccessDenied();\\n }\\n\\n if (attestation.revocationTime != 0) {\\n revert AlreadyRevoked();\\n }\\n\\n attestation.revocationTime = block.timestamp;\\n\\n emit Revoked(attestation.recipient, attester, uuid, attestation.schema);\\n }\\n\\n /**\\n * @dev Calculates a UUID for a given attestation.\\n *\\n * @param attestation The input attestation.\\n *\\n * @return Attestation UUID.\\n */\\n function _getUUID(Attestation memory attestation)\\n private\\n view\\n returns (bytes32)\\n {\\n return\\n keccak256(\\n abi.encodePacked(\\n attestation.schema,\\n attestation.recipient,\\n attestation.attester,\\n attestation.time,\\n attestation.expirationTime,\\n attestation.data,\\n HASH_TERMINATOR,\\n _attestationsCount\\n )\\n );\\n }\\n\\n /**\\n * @dev Returns a slice in an array of attestation UUIDs.\\n *\\n * @param uuids The array of attestation UUIDs.\\n * @param start The offset to start from.\\n * @param length The number of total members to retrieve.\\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\\n *\\n * @return An array of attestation UUIDs.\\n */\\n function _sliceUUIDs(\\n bytes32[] memory uuids,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) private pure returns (bytes32[] memory) {\\n uint256 attestationsLength = uuids.length;\\n if (attestationsLength == 0) {\\n return new bytes32[](0);\\n }\\n\\n if (start >= attestationsLength) {\\n revert InvalidOffset();\\n }\\n\\n uint256 len = length;\\n if (attestationsLength < start + length) {\\n len = attestationsLength - start;\\n }\\n\\n bytes32[] memory res = new bytes32[](len);\\n\\n for (uint256 i = 0; i < len; ++i) {\\n res[i] = uuids[\\n reverseOrder ? attestationsLength - (start + i + 1) : start + i\\n ];\\n }\\n\\n return res;\\n }\\n}\\n\",\"keccak256\":\"0x5a41ca49530d1b4697b5ea58b02900a3297b42a84e49c2753a55b5939c84a415\",\"license\":\"MIT\"},\"contracts/TellerV2Storage.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n// SPDX-License-Identifier: MIT\\n\\nimport { IMarketRegistry } from \\\"./interfaces/IMarketRegistry.sol\\\";\\nimport \\\"./interfaces/IEscrowVault.sol\\\";\\nimport \\\"./interfaces/IReputationManager.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./interfaces/ICollateralManagerV1.sol\\\";\\nimport \\\"./interfaces/ICollateralManagerV2.sol\\\";\\nimport { PaymentType, PaymentCycleType } from \\\"./libraries/V2Calculations.sol\\\";\\nimport \\\"./interfaces/ILenderManager.sol\\\";\\n\\nenum BidState {\\n NONEXISTENT,\\n PENDING,\\n CANCELLED,\\n ACCEPTED,\\n PAID,\\n LIQUIDATED,\\n CLOSED\\n}\\n\\n/**\\n * @notice Represents a total amount for a payment.\\n * @param principal Amount that counts towards the principal.\\n * @param interest Amount that counts toward interest.\\n */\\nstruct Payment {\\n uint256 principal;\\n uint256 interest;\\n}\\n\\n/**\\n * @notice Details about a loan request.\\n * @param borrower Account address who is requesting a loan.\\n * @param receiver Account address who will receive the loan amount.\\n * @param lender Account address who accepted and funded the loan request.\\n * @param marketplaceId ID of the marketplace the bid was submitted to.\\n * @param metadataURI ID of off chain metadata to find additional information of the loan request.\\n * @param loanDetails Struct of the specific loan details.\\n * @param terms Struct of the loan request terms.\\n * @param state Represents the current state of the loan.\\n */\\nstruct Bid {\\n address borrower;\\n address receiver;\\n address lender; // if this is the LenderManager address, we use that .owner() as source of truth\\n uint256 marketplaceId;\\n bytes32 _metadataURI; // DEPRECATED\\n LoanDetails loanDetails;\\n Terms terms;\\n BidState state;\\n PaymentType paymentType;\\n}\\n\\n/**\\n * @notice Details about the loan.\\n * @param lendingToken The token address for the loan.\\n * @param principal The amount of tokens initially lent out.\\n * @param totalRepaid Payment struct that represents the total principal and interest amount repaid.\\n * @param timestamp Timestamp, in seconds, of when the bid was submitted by the borrower.\\n * @param acceptedTimestamp Timestamp, in seconds, of when the bid was accepted by the lender.\\n * @param lastRepaidTimestamp Timestamp, in seconds, of when the last payment was made\\n * @param loanDuration The duration of the loan.\\n */\\nstruct LoanDetails {\\n IERC20 lendingToken;\\n uint256 principal;\\n Payment totalRepaid;\\n uint32 timestamp;\\n uint32 acceptedTimestamp;\\n uint32 lastRepaidTimestamp;\\n uint32 loanDuration;\\n}\\n\\n/**\\n * @notice Information on the terms of a loan request\\n * @param paymentCycleAmount Value of tokens expected to be repaid every payment cycle.\\n * @param paymentCycle Duration, in seconds, of how often a payment must be made.\\n * @param APR Annual percentage rating to be applied on repayments. (10000 == 100%)\\n */\\nstruct Terms {\\n uint256 paymentCycleAmount;\\n uint32 paymentCycle;\\n uint16 APR;\\n}\\n\\nabstract contract TellerV2Storage_G0 {\\n /** Storage Variables */\\n\\n // Current number of bids.\\n uint256 public bidId;\\n\\n // Mapping of bidId to bid information.\\n mapping(uint256 => Bid) public bids;\\n\\n // Mapping of borrowers to borrower requests.\\n mapping(address => uint256[]) public borrowerBids;\\n\\n // Mapping of volume filled by lenders.\\n mapping(address => uint256) public __lenderVolumeFilled; // DEPRECIATED\\n\\n // Volume filled by all lenders.\\n uint256 public __totalVolumeFilled; // DEPRECIATED\\n\\n // List of allowed lending tokens\\n EnumerableSet.AddressSet internal __lendingTokensSet; // DEPRECATED\\n\\n IMarketRegistry public marketRegistry;\\n IReputationManager public reputationManager;\\n\\n // Mapping of borrowers to borrower requests.\\n mapping(address => EnumerableSet.UintSet) internal _borrowerBidsActive;\\n\\n mapping(uint256 => uint32) public bidDefaultDuration;\\n mapping(uint256 => uint32) public bidExpirationTime;\\n\\n // Mapping of volume filled by lenders.\\n // Asset address => Lender address => Volume amount\\n mapping(address => mapping(address => uint256)) public lenderVolumeFilled;\\n\\n // Volume filled by all lenders.\\n // Asset address => Volume amount\\n mapping(address => uint256) public totalVolumeFilled;\\n\\n uint256 public version;\\n\\n // Mapping of metadataURIs by bidIds.\\n // Bid Id => metadataURI string\\n mapping(uint256 => string) public uris;\\n}\\n\\nabstract contract TellerV2Storage_G1 is TellerV2Storage_G0 {\\n // market ID => trusted forwarder\\n mapping(uint256 => address) internal _trustedMarketForwarders;\\n // trusted forwarder => set of pre-approved senders\\n mapping(address => EnumerableSet.AddressSet)\\n internal _approvedForwarderSenders;\\n}\\n\\nabstract contract TellerV2Storage_G2 is TellerV2Storage_G1 {\\n address public lenderCommitmentForwarder; //deprecated\\n}\\n\\nabstract contract TellerV2Storage_G3 is TellerV2Storage_G2 {\\n ICollateralManagerV1 public collateralManagerV1;\\n}\\n\\nabstract contract TellerV2Storage_G4 is TellerV2Storage_G3 {\\n // Address of the lender manager contract\\n ILenderManager public lenderManager;\\n // BidId to payment cycle type (custom or monthly)\\n mapping(uint256 => PaymentCycleType) public bidPaymentCycleType;\\n}\\n\\nabstract contract TellerV2Storage_G5 is TellerV2Storage_G4 {\\n // Address of the lender manager contract\\n IEscrowVault public escrowVault;\\n}\\n\\nabstract contract TellerV2Storage_G6 is TellerV2Storage_G5 {\\n ICollateralManagerV2 public collateralManagerV2;\\n mapping(uint256 => address) public collateralManagerForBid; //if this is zero, that means v1\\n}\\n\\nabstract contract TellerV2Storage is TellerV2Storage_G6 {}\\n\",\"keccak256\":\"0x2df54c48456a3b4e9dc05ae810ecc974847180769ccca28ffcad31b844a5c186\",\"license\":\"MIT\"},\"contracts/Types.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n// SPDX-License-Identifier: MIT\\n\\n// A representation of an empty/uninitialized UUID.\\nbytes32 constant EMPTY_UUID = 0;\\n\",\"keccak256\":\"0x2e4bcf4a965f840193af8729251386c1826cd050411ba4a9e85984a2551fd2ff\",\"license\":\"MIT\"},\"contracts/bundle/interfaces/ICollateralBundle.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity ^0.8.0;\\n\\n/**\\n * Group together arbitrary ERC20, ERC721 and ERC1155 tokens into a single bundle.\\n *\\n * The `Token` struct is a generic type that can describe any ERC20, ERC721 or ERC1155 token.\\n * The `Bundle` struct is a data structure to track a group/bundle of multiple assets i.e. ERC20,\\n * ERC721 and ERC1155 tokens, each described as a `Token`.\\n *\\n * Expressing tokens as the `Token` type, and grouping them as a `Bundle` allows for writing generic\\n * logic to handle any ERC20, ERC721 or ERC1155 tokens.\\n */\\n\\n/// @notice The type of assets that can be bundled.\\nenum CollateralType {\\n ERC20,\\n ERC721,\\n ERC1155\\n}\\n\\n/**\\n * @notice A generic interface to describe any ERC20, ERC721 or ERC1155 token.\\n * @param _collateralType The token type (ERC20 / ERC721 / ERC1155) of the asset.\\n * @param _amount The amount of the asset, if the asset is an ERC20 / ERC1155 fungible token.\\n * @param _tokenId The token Id of the asset, if the asset is an ERC721 / ERC1155 NFT.\\n * @param _collateralAddress The contract address of the asset.\\n *\\n */\\nstruct Collateral {\\n CollateralType _collateralType;\\n uint256 _amount;\\n uint256 _tokenId;\\n address _collateralAddress;\\n}\\n\\ninterface ICollateralBundle {\\n /**\\n * @notice An internal data structure to track a group / bundle of multiple assets i.e. `Token`s.\\n *\\n * @param count The total number of assets i.e. `Collateral` in a bundle.\\n * @param collaterals Mapping from a UID -> to a unique asset i.e. `Collateral` in the bundle.\\n */\\n struct CollateralBundleInfo {\\n uint256 count;\\n mapping(uint256 => Collateral) collaterals;\\n }\\n}\\n\",\"keccak256\":\"0x8f229fe47e8e7c746e6d97c466832c91646122a50cf8bff4f7f9a7e16b174791\",\"license\":\"Apache-2.0\"},\"contracts/interfaces/IASRegistry.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n// SPDX-License-Identifier: MIT\\n\\nimport \\\"./IASResolver.sol\\\";\\n\\n/**\\n * @title The global AS registry interface.\\n */\\ninterface IASRegistry {\\n /**\\n * @title A struct representing a record for a submitted AS (Attestation Schema).\\n */\\n struct ASRecord {\\n // A unique identifier of the AS.\\n bytes32 uuid;\\n // Optional schema resolver.\\n IASResolver resolver;\\n // Auto-incrementing index for reference, assigned by the registry itself.\\n uint256 index;\\n // Custom specification of the AS (e.g., an ABI).\\n bytes schema;\\n }\\n\\n /**\\n * @dev Triggered when a new AS has been registered\\n *\\n * @param uuid The AS UUID.\\n * @param index The AS index.\\n * @param schema The AS schema.\\n * @param resolver An optional AS schema resolver.\\n * @param attester The address of the account used to register the AS.\\n */\\n event Registered(\\n bytes32 indexed uuid,\\n uint256 indexed index,\\n bytes schema,\\n IASResolver resolver,\\n address attester\\n );\\n\\n /**\\n * @dev Submits and reserve a new AS\\n *\\n * @param schema The AS data schema.\\n * @param resolver An optional AS schema resolver.\\n *\\n * @return The UUID of the new AS.\\n */\\n function register(bytes calldata schema, IASResolver resolver)\\n external\\n returns (bytes32);\\n\\n /**\\n * @dev Returns an existing AS by UUID\\n *\\n * @param uuid The UUID of the AS to retrieve.\\n *\\n * @return The AS data members.\\n */\\n function getAS(bytes32 uuid) external view returns (ASRecord memory);\\n\\n /**\\n * @dev Returns the global counter for the total number of attestations\\n *\\n * @return The global counter for the total number of attestations.\\n */\\n function getASCount() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x74752921f592df45c8717d7084627e823b1dbc93bad7187cd3023c9690df7e60\",\"license\":\"MIT\"},\"contracts/interfaces/IASResolver.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n\\n// SPDX-License-Identifier: MIT\\n\\n/**\\n * @title The interface of an optional AS resolver.\\n */\\ninterface IASResolver {\\n /**\\n * @dev Returns whether the resolver supports ETH transfers\\n */\\n function isPayable() external pure returns (bool);\\n\\n /**\\n * @dev Resolves an attestation and verifier whether its data conforms to the spec.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The AS data schema.\\n * @param data The actual attestation data.\\n * @param expirationTime The expiration time of the attestation.\\n * @param msgSender The sender of the original attestation message.\\n *\\n * @return Whether the data is valid according to the scheme.\\n */\\n function resolve(\\n address recipient,\\n bytes calldata schema,\\n bytes calldata data,\\n uint256 expirationTime,\\n address msgSender\\n ) external payable returns (bool);\\n}\\n\",\"keccak256\":\"0xfce671ea099d9f997a69c3447eb4a9c9693d37c5b97e43ada376e614e1c7cb61\",\"license\":\"MIT\"},\"contracts/interfaces/ICollateralManager.sol\":{\"content\":\"// SPDX-Licence-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport { Collateral } from \\\"../bundle/interfaces/ICollateralBundle.sol\\\";\\n\\ninterface ICollateralManager {\\n /**\\n * @notice Checks the validity of a borrower's collateral balance.\\n * @param _bidId The id of the associated bid.\\n * @param _collateralInfo Additional information about the collateral asset.\\n * @return validation_ Boolean indicating if the collateral balance was validated.\\n */\\n function commitCollateral(\\n uint256 _bidId,\\n Collateral[] calldata _collateralInfo\\n ) external returns (bool validation_);\\n\\n /**\\n * @notice Gets the collateral info for a given bid id.\\n * @param _bidId The bidId to return the collateral info for.\\n * @return The stored collateral info.\\n */\\n function getCollateralInfo(uint256 _bidId)\\n external\\n view\\n returns (Collateral[] memory);\\n\\n function getCollateralAmount(uint256 _bidId, address collateralAssetAddress)\\n external\\n view\\n returns (uint256 _amount);\\n\\n /**\\n * @notice Withdraws deposited collateral from the created escrow of a bid.\\n * @param _bidId The id of the bid to withdraw collateral for.\\n */\\n function withdraw(uint256 _bidId) external;\\n\\n /**\\n * @notice Sends the deposited collateral to a lender of a bid.\\n * @notice Can only be called by the protocol.\\n * @param _bidId The id of the liquidated bid.\\n */\\n function lenderClaimCollateral(uint256 _bidId) external;\\n\\n /**\\n * @notice Sends the deposited collateral to a liquidator of a bid.\\n * @notice Can only be called by the protocol.\\n * @param _bidId The id of the liquidated bid.\\n * @param _liquidatorAddress The address of the liquidator to send the collateral to.\\n */\\n function liquidateCollateral(uint256 _bidId, address _liquidatorAddress)\\n external;\\n}\\n\",\"keccak256\":\"0xebefcacd557a58e56e440ca274a0c7ec1d57b4bc2b0d62007d5fbd041cb0aa48\"},\"contracts/interfaces/ICollateralManagerV1.sol\":{\"content\":\"// SPDX-Licence-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\n//import { Collateral } from \\\"./escrow/ICollateralEscrowV1.sol\\\";\\n\\nimport { Collateral } from \\\"../bundle/interfaces/ICollateralBundle.sol\\\";\\n\\nimport \\\"./ICollateralManager.sol\\\";\\n\\ninterface ICollateralManagerV1 is ICollateralManager {\\n function checkBalances(\\n address _borrowerAddress,\\n Collateral[] calldata _collateralInfo\\n ) external returns (bool validated_, bool[] memory checks_);\\n\\n /**\\n * @notice Deploys a new collateral escrow.\\n * @param _bidId The associated bidId of the collateral escrow.\\n */\\n function deployAndDeposit(uint256 _bidId) external;\\n\\n /**\\n * @notice Gets the address of a deployed escrow.\\n * @notice _bidId The bidId to return the escrow for.\\n * @return The address of the escrow.\\n */\\n function getEscrow(uint256 _bidId) external view returns (address);\\n\\n /**\\n * @notice Re-checks the validity of a borrower's collateral balance committed to a bid.\\n * @param _bidId The id of the associated bid.\\n * @return validation_ Boolean indicating if the collateral balance was validated.\\n */\\n function revalidateCollateral(uint256 _bidId) external returns (bool);\\n}\\n\",\"keccak256\":\"0xc4abc552dd8fb1d7b6f0be2947bb82586806a6f53112907eb391b6713b0290eb\"},\"contracts/interfaces/ICollateralManagerV2.sol\":{\"content\":\"// SPDX-Licence-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./ICollateralManager.sol\\\";\\n\\n//use TokenBundle\\n/*\\nenum CollateralType {\\n ERC20,\\n ERC721,\\n ERC1155\\n}\\n\\nstruct Collateral {\\n CollateralType _collateralType;\\n uint256 _amount;\\n uint256 _tokenId;\\n address _collateralAddress;\\n}*/\\n\\nimport { Collateral } from \\\"../bundle/interfaces/ICollateralBundle.sol\\\";\\n\\ninterface ICollateralManagerV2 is ICollateralManager {\\n /**\\n * @notice Deploys a new collateral escrow.\\n * @param _bidId The associated bidId of the collateral escrow.\\n */\\n function depositCollateral(uint256 _bidId) external;\\n\\n /**\\n * @notice Gets the address of a deployed escrow.\\n * @notice _bidId The bidId to return the escrow for.\\n * @return The address of the escrow.\\n */\\n // function getEscrow(uint256 _bidId) external view returns (address);\\n\\n /**\\n * @notice Gets the collateral info for a given bid id.\\n * @param _bidId The bidId to return the collateral info for.\\n * @return The stored collateral info.\\n */\\n function getCollateralInfo(uint256 _bidId)\\n external\\n view\\n returns (Collateral[] memory);\\n\\n function getCollateralAmount(uint256 _bidId, address collateralAssetAddress)\\n external\\n view\\n returns (uint256 _amount);\\n}\\n\",\"keccak256\":\"0xca255d1c590b4bfbbcdb46bb1d8efcd52a63feb404a7880d0142566df86ee5f2\"},\"contracts/interfaces/IEAS.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n// SPDX-License-Identifier: MIT\\n\\nimport \\\"./IASRegistry.sol\\\";\\nimport \\\"./IEASEIP712Verifier.sol\\\";\\n\\n/**\\n * @title EAS - Ethereum Attestation Service interface\\n */\\ninterface IEAS {\\n /**\\n * @dev A struct representing a single attestation.\\n */\\n struct Attestation {\\n // A unique identifier of the attestation.\\n bytes32 uuid;\\n // A unique identifier of the AS.\\n bytes32 schema;\\n // The recipient of the attestation.\\n address recipient;\\n // The attester/sender of the attestation.\\n address attester;\\n // The time when the attestation was created (Unix timestamp).\\n uint256 time;\\n // The time when the attestation expires (Unix timestamp).\\n uint256 expirationTime;\\n // The time when the attestation was revoked (Unix timestamp).\\n uint256 revocationTime;\\n // The UUID of the related attestation.\\n bytes32 refUUID;\\n // Custom attestation data.\\n bytes data;\\n }\\n\\n /**\\n * @dev Triggered when an attestation has been made.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param attester The attesting account.\\n * @param uuid The UUID the revoked attestation.\\n * @param schema The UUID of the AS.\\n */\\n event Attested(\\n address indexed recipient,\\n address indexed attester,\\n bytes32 uuid,\\n bytes32 indexed schema\\n );\\n\\n /**\\n * @dev Triggered when an attestation has been revoked.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param attester The attesting account.\\n * @param schema The UUID of the AS.\\n * @param uuid The UUID the revoked attestation.\\n */\\n event Revoked(\\n address indexed recipient,\\n address indexed attester,\\n bytes32 uuid,\\n bytes32 indexed schema\\n );\\n\\n /**\\n * @dev Returns the address of the AS global registry.\\n *\\n * @return The address of the AS global registry.\\n */\\n function getASRegistry() external view returns (IASRegistry);\\n\\n /**\\n * @dev Returns the address of the EIP712 verifier used to verify signed attestations.\\n *\\n * @return The address of the EIP712 verifier used to verify signed attestations.\\n */\\n function getEIP712Verifier() external view returns (IEASEIP712Verifier);\\n\\n /**\\n * @dev Returns the global counter for the total number of attestations.\\n *\\n * @return The global counter for the total number of attestations.\\n */\\n function getAttestationsCount() external view returns (uint256);\\n\\n /**\\n * @dev Attests to a specific AS.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n * @param expirationTime The expiration time of the attestation.\\n * @param refUUID An optional related attestation's UUID.\\n * @param data Additional custom data.\\n *\\n * @return The UUID of the new attestation.\\n */\\n function attest(\\n address recipient,\\n bytes32 schema,\\n uint256 expirationTime,\\n bytes32 refUUID,\\n bytes calldata data\\n ) external payable returns (bytes32);\\n\\n /**\\n * @dev Attests to a specific AS using a provided EIP712 signature.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n * @param expirationTime The expiration time of the attestation.\\n * @param refUUID An optional related attestation's UUID.\\n * @param data Additional custom data.\\n * @param attester The attesting account.\\n * @param v The recovery ID.\\n * @param r The x-coordinate of the nonce R.\\n * @param s The signature data.\\n *\\n * @return The UUID of the new attestation.\\n */\\n function attestByDelegation(\\n address recipient,\\n bytes32 schema,\\n uint256 expirationTime,\\n bytes32 refUUID,\\n bytes calldata data,\\n address attester,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external payable returns (bytes32);\\n\\n /**\\n * @dev Revokes an existing attestation to a specific AS.\\n *\\n * @param uuid The UUID of the attestation to revoke.\\n */\\n function revoke(bytes32 uuid) external;\\n\\n /**\\n * @dev Attests to a specific AS using a provided EIP712 signature.\\n *\\n * @param uuid The UUID of the attestation to revoke.\\n * @param attester The attesting account.\\n * @param v The recovery ID.\\n * @param r The x-coordinate of the nonce R.\\n * @param s The signature data.\\n */\\n function revokeByDelegation(\\n bytes32 uuid,\\n address attester,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns an existing attestation by UUID.\\n *\\n * @param uuid The UUID of the attestation to retrieve.\\n *\\n * @return The attestation data members.\\n */\\n function getAttestation(bytes32 uuid)\\n external\\n view\\n returns (Attestation memory);\\n\\n /**\\n * @dev Checks whether an attestation exists.\\n *\\n * @param uuid The UUID of the attestation to retrieve.\\n *\\n * @return Whether an attestation exists.\\n */\\n function isAttestationValid(bytes32 uuid) external view returns (bool);\\n\\n /**\\n * @dev Checks whether an attestation is active.\\n *\\n * @param uuid The UUID of the attestation to retrieve.\\n *\\n * @return Whether an attestation is active.\\n */\\n function isAttestationActive(bytes32 uuid) external view returns (bool);\\n\\n /**\\n * @dev Returns all received attestation UUIDs.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n * @param start The offset to start from.\\n * @param length The number of total members to retrieve.\\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\\n *\\n * @return An array of attestation UUIDs.\\n */\\n function getReceivedAttestationUUIDs(\\n address recipient,\\n bytes32 schema,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view returns (bytes32[] memory);\\n\\n /**\\n * @dev Returns the number of received attestation UUIDs.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n *\\n * @return The number of attestations.\\n */\\n function getReceivedAttestationUUIDsCount(address recipient, bytes32 schema)\\n external\\n view\\n returns (uint256);\\n\\n /**\\n * @dev Returns all sent attestation UUIDs.\\n *\\n * @param attester The attesting account.\\n * @param schema The UUID of the AS.\\n * @param start The offset to start from.\\n * @param length The number of total members to retrieve.\\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\\n *\\n * @return An array of attestation UUIDs.\\n */\\n function getSentAttestationUUIDs(\\n address attester,\\n bytes32 schema,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view returns (bytes32[] memory);\\n\\n /**\\n * @dev Returns the number of sent attestation UUIDs.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n *\\n * @return The number of attestations.\\n */\\n function getSentAttestationUUIDsCount(address recipient, bytes32 schema)\\n external\\n view\\n returns (uint256);\\n\\n /**\\n * @dev Returns all attestations related to a specific attestation.\\n *\\n * @param uuid The UUID of the attestation to retrieve.\\n * @param start The offset to start from.\\n * @param length The number of total members to retrieve.\\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\\n *\\n * @return An array of attestation UUIDs.\\n */\\n function getRelatedAttestationUUIDs(\\n bytes32 uuid,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view returns (bytes32[] memory);\\n\\n /**\\n * @dev Returns the number of related attestation UUIDs.\\n *\\n * @param uuid The UUID of the attestation to retrieve.\\n *\\n * @return The number of related attestations.\\n */\\n function getRelatedAttestationUUIDsCount(bytes32 uuid)\\n external\\n view\\n returns (uint256);\\n\\n /**\\n * @dev Returns all per-schema attestation UUIDs.\\n *\\n * @param schema The UUID of the AS.\\n * @param start The offset to start from.\\n * @param length The number of total members to retrieve.\\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\\n *\\n * @return An array of attestation UUIDs.\\n */\\n function getSchemaAttestationUUIDs(\\n bytes32 schema,\\n uint256 start,\\n uint256 length,\\n bool reverseOrder\\n ) external view returns (bytes32[] memory);\\n\\n /**\\n * @dev Returns the number of per-schema attestation UUIDs.\\n *\\n * @param schema The UUID of the AS.\\n *\\n * @return The number of attestations.\\n */\\n function getSchemaAttestationUUIDsCount(bytes32 schema)\\n external\\n view\\n returns (uint256);\\n}\\n\",\"keccak256\":\"0x5db90829269f806ed14a6c638f38d4aac1fa0f85829b34a2fcddd5200261c148\",\"license\":\"MIT\"},\"contracts/interfaces/IEASEIP712Verifier.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n\\n// SPDX-License-Identifier: MIT\\n\\n/**\\n * @title EIP712 typed signatures verifier for EAS delegated attestations interface.\\n */\\ninterface IEASEIP712Verifier {\\n /**\\n * @dev Returns the current nonce per-account.\\n *\\n * @param account The requested accunt.\\n *\\n * @return The current nonce.\\n */\\n function getNonce(address account) external view returns (uint256);\\n\\n /**\\n * @dev Verifies signed attestation.\\n *\\n * @param recipient The recipient of the attestation.\\n * @param schema The UUID of the AS.\\n * @param expirationTime The expiration time of the attestation.\\n * @param refUUID An optional related attestation's UUID.\\n * @param data Additional custom data.\\n * @param attester The attesting account.\\n * @param v The recovery ID.\\n * @param r The x-coordinate of the nonce R.\\n * @param s The signature data.\\n */\\n function attest(\\n address recipient,\\n bytes32 schema,\\n uint256 expirationTime,\\n bytes32 refUUID,\\n bytes calldata data,\\n address attester,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Verifies signed revocations.\\n *\\n * @param uuid The UUID of the attestation to revoke.\\n * @param attester The attesting account.\\n * @param v The recovery ID.\\n * @param r The x-coordinate of the nonce R.\\n * @param s The signature data.\\n */\\n function revoke(\\n bytes32 uuid,\\n address attester,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n}\\n\",\"keccak256\":\"0xeca3ac3bacec52af15b2c86c5bf1a1be315aade51fa86f95da2b426b28486b1e\",\"license\":\"MIT\"},\"contracts/interfaces/IEscrowVault.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\ninterface IEscrowVault {\\n /**\\n * @notice Deposit tokens on behalf of another account\\n * @param account The address of the account\\n * @param token The address of the token\\n * @param amount The amount to increase the balance\\n */\\n function deposit(address account, address token, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0x8c95f089fb12f263e98b26c0ce9983a6814736c9ec8a6de603b397fd64c29a9a\",\"license\":\"MIT\"},\"contracts/interfaces/ILenderManager.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n\\n// SPDX-License-Identifier: MIT\\nimport \\\"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\\\";\\n\\nabstract contract ILenderManager is IERC721Upgradeable {\\n /**\\n * @notice Registers a new active lender for a loan, minting the nft.\\n * @param _bidId The id for the loan to set.\\n * @param _newLender The address of the new active lender.\\n */\\n function registerLoan(uint256 _bidId, address _newLender) external virtual;\\n}\\n\",\"keccak256\":\"0xceb1ea2ef4c6e2ad7986db84de49c959e8d59844563d27daca5b8d78b732a8f7\",\"license\":\"MIT\"},\"contracts/interfaces/IMarketRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../EAS/TellerAS.sol\\\";\\nimport { PaymentType, PaymentCycleType } from \\\"../libraries/V2Calculations.sol\\\";\\n\\ninterface IMarketRegistry {\\n function initialize(TellerAS tellerAs) external;\\n\\n function isVerifiedLender(uint256 _marketId, address _lender)\\n external\\n view\\n returns (bool, bytes32);\\n\\n function isMarketOpen(uint256 _marketId) external view returns (bool);\\n\\n function isMarketClosed(uint256 _marketId) external view returns (bool);\\n\\n function isVerifiedBorrower(uint256 _marketId, address _borrower)\\n external\\n view\\n returns (bool, bytes32);\\n\\n function getMarketOwner(uint256 _marketId) external view returns (address);\\n\\n function getMarketFeeRecipient(uint256 _marketId)\\n external\\n view\\n returns (address);\\n\\n function getMarketURI(uint256 _marketId)\\n external\\n view\\n returns (string memory);\\n\\n function getPaymentCycle(uint256 _marketId)\\n external\\n view\\n returns (uint32, PaymentCycleType);\\n\\n function getPaymentDefaultDuration(uint256 _marketId)\\n external\\n view\\n returns (uint32);\\n\\n function getBidExpirationTime(uint256 _marketId)\\n external\\n view\\n returns (uint32);\\n\\n function getMarketplaceFee(uint256 _marketId)\\n external\\n view\\n returns (uint16);\\n\\n function getPaymentType(uint256 _marketId)\\n external\\n view\\n returns (PaymentType);\\n\\n function createMarket(\\n address _initialOwner,\\n uint32 _paymentCycleDuration,\\n uint32 _paymentDefaultDuration,\\n uint32 _bidExpirationTime,\\n uint16 _feePercent,\\n bool _requireLenderAttestation,\\n bool _requireBorrowerAttestation,\\n PaymentType _paymentType,\\n PaymentCycleType _paymentCycleType,\\n string calldata _uri\\n ) external returns (uint256 marketId_);\\n\\n function createMarket(\\n address _initialOwner,\\n uint32 _paymentCycleDuration,\\n uint32 _paymentDefaultDuration,\\n uint32 _bidExpirationTime,\\n uint16 _feePercent,\\n bool _requireLenderAttestation,\\n bool _requireBorrowerAttestation,\\n string calldata _uri\\n ) external returns (uint256 marketId_);\\n\\n function closeMarket(uint256 _marketId) external;\\n}\\n\",\"keccak256\":\"0x2a17561a47cb3517f2820d68d9bbcd86dcd21c59cad7208581004ecd91d5478a\",\"license\":\"MIT\"},\"contracts/interfaces/IReputationManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum RepMark {\\n Good,\\n Delinquent,\\n Default\\n}\\n\\ninterface IReputationManager {\\n function initialize(address protocolAddress) external;\\n\\n function getDelinquentLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function getDefaultedLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function getCurrentDelinquentLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function getCurrentDefaultLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function updateAccountReputation(address _account) external;\\n\\n function updateAccountReputation(address _account, uint256 _bidId)\\n external\\n returns (RepMark);\\n}\\n\",\"keccak256\":\"0x8d6e50fd460912231e53135b4459aa2f6f16007ae8deb32bc2cee1e88311a8d8\",\"license\":\"MIT\"},\"contracts/libraries/DateTimeLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.6.0 <0.9.0;\\n\\n// ----------------------------------------------------------------------------\\n// BokkyPooBah's DateTime Library v1.01\\n//\\n// A gas-efficient Solidity date and time library\\n//\\n// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary\\n//\\n// Tested date range 1970/01/01 to 2345/12/31\\n//\\n// Conventions:\\n// Unit | Range | Notes\\n// :-------- |:-------------:|:-----\\n// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC\\n// year | 1970 ... 2345 |\\n// month | 1 ... 12 |\\n// day | 1 ... 31 |\\n// hour | 0 ... 23 |\\n// minute | 0 ... 59 |\\n// second | 0 ... 59 |\\n// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday\\n//\\n//\\n// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.\\n// ----------------------------------------------------------------------------\\n\\nlibrary BokkyPooBahsDateTimeLibrary {\\n uint constant SECONDS_PER_DAY = 24 * 60 * 60;\\n uint constant SECONDS_PER_HOUR = 60 * 60;\\n uint constant SECONDS_PER_MINUTE = 60;\\n int constant OFFSET19700101 = 2440588;\\n\\n uint constant DOW_MON = 1;\\n uint constant DOW_TUE = 2;\\n uint constant DOW_WED = 3;\\n uint constant DOW_THU = 4;\\n uint constant DOW_FRI = 5;\\n uint constant DOW_SAT = 6;\\n uint constant DOW_SUN = 7;\\n\\n // ------------------------------------------------------------------------\\n // Calculate the number of days from 1970/01/01 to year/month/day using\\n // the date conversion algorithm from\\n // https://aa.usno.navy.mil/faq/JD_formula.html\\n // and subtracting the offset 2440588 so that 1970/01/01 is day 0\\n //\\n // days = day\\n // - 32075\\n // + 1461 * (year + 4800 + (month - 14) / 12) / 4\\n // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12\\n // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4\\n // - offset\\n // ------------------------------------------------------------------------\\n function _daysFromDate(uint year, uint month, uint day)\\n internal\\n pure\\n returns (uint _days)\\n {\\n require(year >= 1970);\\n int _year = int(year);\\n int _month = int(month);\\n int _day = int(day);\\n\\n int __days = _day -\\n 32075 +\\n (1461 * (_year + 4800 + (_month - 14) / 12)) /\\n 4 +\\n (367 * (_month - 2 - ((_month - 14) / 12) * 12)) /\\n 12 -\\n (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) /\\n 4 -\\n OFFSET19700101;\\n\\n _days = uint(__days);\\n }\\n\\n // ------------------------------------------------------------------------\\n // Calculate year/month/day from the number of days since 1970/01/01 using\\n // the date conversion algorithm from\\n // http://aa.usno.navy.mil/faq/docs/JD_Formula.php\\n // and adding the offset 2440588 so that 1970/01/01 is day 0\\n //\\n // int L = days + 68569 + offset\\n // int N = 4 * L / 146097\\n // L = L - (146097 * N + 3) / 4\\n // year = 4000 * (L + 1) / 1461001\\n // L = L - 1461 * year / 4 + 31\\n // month = 80 * L / 2447\\n // dd = L - 2447 * month / 80\\n // L = month / 11\\n // month = month + 2 - 12 * L\\n // year = 100 * (N - 49) + year + L\\n // ------------------------------------------------------------------------\\n function _daysToDate(uint _days)\\n internal\\n pure\\n returns (uint year, uint month, uint day)\\n {\\n int __days = int(_days);\\n\\n int L = __days + 68569 + OFFSET19700101;\\n int N = (4 * L) / 146097;\\n L = L - (146097 * N + 3) / 4;\\n int _year = (4000 * (L + 1)) / 1461001;\\n L = L - (1461 * _year) / 4 + 31;\\n int _month = (80 * L) / 2447;\\n int _day = L - (2447 * _month) / 80;\\n L = _month / 11;\\n _month = _month + 2 - 12 * L;\\n _year = 100 * (N - 49) + _year + L;\\n\\n year = uint(_year);\\n month = uint(_month);\\n day = uint(_day);\\n }\\n\\n function timestampFromDate(uint year, uint month, uint day)\\n internal\\n pure\\n returns (uint timestamp)\\n {\\n timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;\\n }\\n\\n function timestampFromDateTime(\\n uint year,\\n uint month,\\n uint day,\\n uint hour,\\n uint minute,\\n uint second\\n ) internal pure returns (uint timestamp) {\\n timestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n hour *\\n SECONDS_PER_HOUR +\\n minute *\\n SECONDS_PER_MINUTE +\\n second;\\n }\\n\\n function timestampToDate(uint timestamp)\\n internal\\n pure\\n returns (uint year, uint month, uint day)\\n {\\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function timestampToDateTime(uint timestamp)\\n internal\\n pure\\n returns (\\n uint year,\\n uint month,\\n uint day,\\n uint hour,\\n uint minute,\\n uint second\\n )\\n {\\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n uint secs = timestamp % SECONDS_PER_DAY;\\n hour = secs / SECONDS_PER_HOUR;\\n secs = secs % SECONDS_PER_HOUR;\\n minute = secs / SECONDS_PER_MINUTE;\\n second = secs % SECONDS_PER_MINUTE;\\n }\\n\\n function isValidDate(uint year, uint month, uint day)\\n internal\\n pure\\n returns (bool valid)\\n {\\n if (year >= 1970 && month > 0 && month <= 12) {\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > 0 && day <= daysInMonth) {\\n valid = true;\\n }\\n }\\n }\\n\\n function isValidDateTime(\\n uint year,\\n uint month,\\n uint day,\\n uint hour,\\n uint minute,\\n uint second\\n ) internal pure returns (bool valid) {\\n if (isValidDate(year, month, day)) {\\n if (hour < 24 && minute < 60 && second < 60) {\\n valid = true;\\n }\\n }\\n }\\n\\n function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {\\n (uint year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n leapYear = _isLeapYear(year);\\n }\\n\\n function _isLeapYear(uint year) internal pure returns (bool leapYear) {\\n leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);\\n }\\n\\n function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {\\n weekDay = getDayOfWeek(timestamp) <= DOW_FRI;\\n }\\n\\n function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {\\n weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;\\n }\\n\\n function getDaysInMonth(uint timestamp)\\n internal\\n pure\\n returns (uint daysInMonth)\\n {\\n (uint year, uint month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n daysInMonth = _getDaysInMonth(year, month);\\n }\\n\\n function _getDaysInMonth(uint year, uint month)\\n internal\\n pure\\n returns (uint daysInMonth)\\n {\\n if (\\n month == 1 ||\\n month == 3 ||\\n month == 5 ||\\n month == 7 ||\\n month == 8 ||\\n month == 10 ||\\n month == 12\\n ) {\\n daysInMonth = 31;\\n } else if (month != 2) {\\n daysInMonth = 30;\\n } else {\\n daysInMonth = _isLeapYear(year) ? 29 : 28;\\n }\\n }\\n\\n // 1 = Monday, 7 = Sunday\\n function getDayOfWeek(uint timestamp)\\n internal\\n pure\\n returns (uint dayOfWeek)\\n {\\n uint _days = timestamp / SECONDS_PER_DAY;\\n dayOfWeek = ((_days + 3) % 7) + 1;\\n }\\n\\n function getYear(uint timestamp) internal pure returns (uint year) {\\n (year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function getMonth(uint timestamp) internal pure returns (uint month) {\\n (, month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function getDay(uint timestamp) internal pure returns (uint day) {\\n (, , day) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function getHour(uint timestamp) internal pure returns (uint hour) {\\n uint secs = timestamp % SECONDS_PER_DAY;\\n hour = secs / SECONDS_PER_HOUR;\\n }\\n\\n function getMinute(uint timestamp) internal pure returns (uint minute) {\\n uint secs = timestamp % SECONDS_PER_HOUR;\\n minute = secs / SECONDS_PER_MINUTE;\\n }\\n\\n function getSecond(uint timestamp) internal pure returns (uint second) {\\n second = timestamp % SECONDS_PER_MINUTE;\\n }\\n\\n function addYears(uint timestamp, uint _years)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n year += _years;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addMonths(uint timestamp, uint _months)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n month += _months;\\n year += (month - 1) / 12;\\n month = ((month - 1) % 12) + 1;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addDays(uint timestamp, uint _days)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _days * SECONDS_PER_DAY;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addHours(uint timestamp, uint _hours)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addMinutes(uint timestamp, uint _minutes)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addSeconds(uint timestamp, uint _seconds)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _seconds;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function subYears(uint timestamp, uint _years)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n year -= _years;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subMonths(uint timestamp, uint _months)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n uint yearMonth = year * 12 + (month - 1) - _months;\\n year = yearMonth / 12;\\n month = (yearMonth % 12) + 1;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subDays(uint timestamp, uint _days)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _days * SECONDS_PER_DAY;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subHours(uint timestamp, uint _hours)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subMinutes(uint timestamp, uint _minutes)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subSeconds(uint timestamp, uint _seconds)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _seconds;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function diffYears(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _years)\\n {\\n require(fromTimestamp <= toTimestamp);\\n (uint fromYear, , ) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);\\n (uint toYear, , ) = _daysToDate(toTimestamp / SECONDS_PER_DAY);\\n _years = toYear - fromYear;\\n }\\n\\n function diffMonths(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _months)\\n {\\n require(fromTimestamp <= toTimestamp);\\n (uint fromYear, uint fromMonth, ) = _daysToDate(\\n fromTimestamp / SECONDS_PER_DAY\\n );\\n (uint toYear, uint toMonth, ) = _daysToDate(\\n toTimestamp / SECONDS_PER_DAY\\n );\\n _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;\\n }\\n\\n function diffDays(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _days)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;\\n }\\n\\n function diffHours(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _hours)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;\\n }\\n\\n function diffMinutes(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _minutes)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;\\n }\\n\\n function diffSeconds(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _seconds)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _seconds = toTimestamp - fromTimestamp;\\n }\\n}\\n\",\"keccak256\":\"0xf194df8ea9946a5bb3300223629b7e4959c1f20bacba27b3dc5f6dd2a160147a\",\"license\":\"MIT\"},\"contracts/libraries/NumbersLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n// Libraries\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\nimport { Math } from \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\nimport \\\"./WadRayMath.sol\\\";\\n\\n/**\\n * @dev Utility library for uint256 numbers\\n *\\n * @author develop@teller.finance\\n */\\nlibrary NumbersLib {\\n using WadRayMath for uint256;\\n\\n /**\\n * @dev It represents 100% with 2 decimal places.\\n */\\n uint16 internal constant PCT_100 = 10000;\\n\\n function percentFactor(uint256 decimals) internal pure returns (uint256) {\\n return 100 * (10**decimals);\\n }\\n\\n /**\\n * @notice Returns a percentage value of a number.\\n * @param self The number to get a percentage of.\\n * @param percentage The percentage value to calculate with 2 decimal places (10000 = 100%).\\n */\\n function percent(uint256 self, uint16 percentage)\\n internal\\n pure\\n returns (uint256)\\n {\\n return percent(self, percentage, 2);\\n }\\n\\n /**\\n * @notice Returns a percentage value of a number.\\n * @param self The number to get a percentage of.\\n * @param percentage The percentage value to calculate with.\\n * @param decimals The number of decimals the percentage value is in.\\n */\\n function percent(uint256 self, uint256 percentage, uint256 decimals)\\n internal\\n pure\\n returns (uint256)\\n {\\n return (self * percentage) / percentFactor(decimals);\\n }\\n\\n /**\\n * @notice it returns the absolute number of a specified parameter\\n * @param self the number to be returned in it's absolute\\n * @return the absolute number\\n */\\n function abs(int256 self) internal pure returns (uint256) {\\n return self >= 0 ? uint256(self) : uint256(-1 * self);\\n }\\n\\n /**\\n * @notice Returns a ratio percentage of {num1} to {num2}.\\n * @dev Returned value is type uint16.\\n * @param num1 The number used to get the ratio for.\\n * @param num2 The number used to get the ratio from.\\n * @return Ratio percentage with 2 decimal places (10000 = 100%).\\n */\\n function ratioOf(uint256 num1, uint256 num2)\\n internal\\n pure\\n returns (uint16)\\n {\\n return SafeCast.toUint16(ratioOf(num1, num2, 2));\\n }\\n\\n /**\\n * @notice Returns a ratio percentage of {num1} to {num2}.\\n * @param num1 The number used to get the ratio for.\\n * @param num2 The number used to get the ratio from.\\n * @param decimals The number of decimals the percentage value is returned in.\\n * @return Ratio percentage value.\\n */\\n function ratioOf(uint256 num1, uint256 num2, uint256 decimals)\\n internal\\n pure\\n returns (uint256)\\n {\\n if (num2 == 0) return 0;\\n return (num1 * percentFactor(decimals)) / num2;\\n }\\n\\n /**\\n * @notice Calculates the payment amount for a cycle duration.\\n * The formula is calculated based on the standard Estimated Monthly Installment (https://en.wikipedia.org/wiki/Equated_monthly_installment)\\n * EMI = [P x R x (1+R)^N]/[(1+R)^N-1]\\n * @param principal The starting amount that is owed on the loan.\\n * @param loanDuration The length of the loan.\\n * @param cycleDuration The length of the loan's payment cycle.\\n * @param apr The annual percentage rate of the loan.\\n */\\n function pmt(\\n uint256 principal,\\n uint32 loanDuration,\\n uint32 cycleDuration,\\n uint16 apr,\\n uint256 daysInYear\\n ) internal pure returns (uint256) {\\n require(\\n loanDuration >= cycleDuration,\\n \\\"PMT: cycle duration < loan duration\\\"\\n );\\n if (apr == 0)\\n return\\n Math.mulDiv(\\n principal,\\n cycleDuration,\\n loanDuration,\\n Math.Rounding.Up\\n );\\n\\n // Number of payment cycles for the duration of the loan\\n uint256 n = Math.ceilDiv(loanDuration, cycleDuration);\\n\\n uint256 one = WadRayMath.wad();\\n uint256 r = WadRayMath.pctToWad(apr).wadMul(cycleDuration).wadDiv(\\n daysInYear\\n );\\n uint256 exp = (one + r).wadPow(n);\\n uint256 numerator = principal.wadMul(r).wadMul(exp);\\n uint256 denominator = exp - one;\\n\\n return numerator.wadDiv(denominator);\\n }\\n}\\n\",\"keccak256\":\"0x78009ffb3737ab7615a1e38a26635d6c06b65b7b7959af46d6ef840d220e70cf\",\"license\":\"MIT\"},\"contracts/libraries/V2Calculations.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n\\n// SPDX-License-Identifier: MIT\\n\\n// Libraries\\nimport \\\"./NumbersLib.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\nimport { Bid } from \\\"../TellerV2Storage.sol\\\";\\nimport { BokkyPooBahsDateTimeLibrary as BPBDTL } from \\\"./DateTimeLib.sol\\\";\\n\\nenum PaymentType {\\n EMI,\\n Bullet\\n}\\n\\nenum PaymentCycleType {\\n Seconds,\\n Monthly\\n}\\n\\nlibrary V2Calculations {\\n using NumbersLib for uint256;\\n\\n /**\\n * @notice Returns the timestamp of the last payment made for a loan.\\n * @param _bid The loan bid struct to get the timestamp for.\\n */\\n function lastRepaidTimestamp(Bid storage _bid)\\n internal\\n view\\n returns (uint32)\\n {\\n return\\n _bid.loanDetails.lastRepaidTimestamp == 0\\n ? _bid.loanDetails.acceptedTimestamp\\n : _bid.loanDetails.lastRepaidTimestamp;\\n }\\n\\n /**\\n * @notice Calculates the amount owed for a loan.\\n * @param _bid The loan bid struct to get the owed amount for.\\n * @param _timestamp The timestamp at which to get the owed amount at.\\n * @param _paymentCycleType The payment cycle type of the loan (Seconds or Monthly).\\n */\\n function calculateAmountOwed(\\n Bid storage _bid,\\n uint256 _timestamp,\\n PaymentCycleType _paymentCycleType\\n )\\n internal\\n view\\n returns (\\n uint256 owedPrincipal_,\\n uint256 duePrincipal_,\\n uint256 interest_\\n )\\n {\\n // Total principal left to pay\\n return\\n calculateAmountOwed(\\n _bid,\\n lastRepaidTimestamp(_bid),\\n _timestamp,\\n _paymentCycleType\\n );\\n }\\n\\n function calculateAmountOwed(\\n Bid storage _bid,\\n uint256 _lastRepaidTimestamp,\\n uint256 _timestamp,\\n PaymentCycleType _paymentCycleType\\n )\\n internal\\n view\\n returns (\\n uint256 owedPrincipal_,\\n uint256 duePrincipal_,\\n uint256 interest_\\n )\\n {\\n owedPrincipal_ =\\n _bid.loanDetails.principal -\\n _bid.loanDetails.totalRepaid.principal;\\n\\n uint256 daysInYear = _paymentCycleType == PaymentCycleType.Monthly\\n ? 360 days\\n : 365 days;\\n\\n uint256 interestOwedInAYear = owedPrincipal_.percent(_bid.terms.APR);\\n uint256 owedTime = _timestamp - uint256(_lastRepaidTimestamp);\\n interest_ = (interestOwedInAYear * owedTime) / daysInYear;\\n\\n bool isLastPaymentCycle;\\n {\\n uint256 lastPaymentCycleDuration = _bid.loanDetails.loanDuration %\\n _bid.terms.paymentCycle;\\n if (lastPaymentCycleDuration == 0) {\\n lastPaymentCycleDuration = _bid.terms.paymentCycle;\\n }\\n\\n uint256 endDate = uint256(_bid.loanDetails.acceptedTimestamp) +\\n uint256(_bid.loanDetails.loanDuration);\\n uint256 lastPaymentCycleStart = endDate -\\n uint256(lastPaymentCycleDuration);\\n\\n isLastPaymentCycle =\\n uint256(_timestamp) > lastPaymentCycleStart ||\\n owedPrincipal_ + interest_ <= _bid.terms.paymentCycleAmount;\\n }\\n\\n if (_bid.paymentType == PaymentType.Bullet) {\\n if (isLastPaymentCycle) {\\n duePrincipal_ = owedPrincipal_;\\n }\\n } else {\\n // Default to PaymentType.EMI\\n // Max payable amount in a cycle\\n // NOTE: the last cycle could have less than the calculated payment amount\\n\\n uint256 owedAmount = isLastPaymentCycle\\n ? owedPrincipal_ + interest_\\n : (_bid.terms.paymentCycleAmount * owedTime) /\\n _bid.terms.paymentCycle;\\n\\n duePrincipal_ = Math.min(owedAmount - interest_, owedPrincipal_);\\n }\\n }\\n\\n /**\\n * @notice Calculates the amount owed for a loan for the next payment cycle.\\n * @param _type The payment type of the loan.\\n * @param _cycleType The cycle type set for the loan. (Seconds or Monthly)\\n * @param _principal The starting amount that is owed on the loan.\\n * @param _duration The length of the loan.\\n * @param _paymentCycle The length of the loan's payment cycle.\\n * @param _apr The annual percentage rate of the loan.\\n */\\n function calculatePaymentCycleAmount(\\n PaymentType _type,\\n PaymentCycleType _cycleType,\\n uint256 _principal,\\n uint32 _duration,\\n uint32 _paymentCycle,\\n uint16 _apr\\n ) internal returns (uint256) {\\n uint256 daysInYear = _cycleType == PaymentCycleType.Monthly\\n ? 360 days\\n : 365 days;\\n if (_type == PaymentType.Bullet) {\\n return\\n _principal.percent(_apr).percent(\\n uint256(_paymentCycle).ratioOf(daysInYear, 10),\\n 10\\n );\\n }\\n // Default to PaymentType.EMI\\n return\\n NumbersLib.pmt(\\n _principal,\\n _duration,\\n _paymentCycle,\\n _apr,\\n daysInYear\\n );\\n }\\n\\n function calculateNextDueDate(\\n uint32 _acceptedTimestamp,\\n uint32 _paymentCycle,\\n uint32 _loanDuration,\\n uint32 _lastRepaidTimestamp,\\n PaymentCycleType _bidPaymentCycleType\\n ) public view returns (uint32 dueDate_) {\\n // Calculate due date if payment cycle is set to monthly\\n if (_bidPaymentCycleType == PaymentCycleType.Monthly) {\\n // Calculate the cycle number the last repayment was made\\n uint256 lastPaymentCycle = BPBDTL.diffMonths(\\n _acceptedTimestamp,\\n _lastRepaidTimestamp\\n );\\n if (\\n BPBDTL.getDay(_lastRepaidTimestamp) >\\n BPBDTL.getDay(_acceptedTimestamp)\\n ) {\\n lastPaymentCycle += 2;\\n } else {\\n lastPaymentCycle += 1;\\n }\\n\\n dueDate_ = uint32(\\n BPBDTL.addMonths(_acceptedTimestamp, lastPaymentCycle)\\n );\\n } else if (_bidPaymentCycleType == PaymentCycleType.Seconds) {\\n // Start with the original due date being 1 payment cycle since bid was accepted\\n dueDate_ = _acceptedTimestamp + _paymentCycle;\\n // Calculate the cycle number the last repayment was made\\n uint32 delta = _lastRepaidTimestamp - _acceptedTimestamp;\\n if (delta > 0) {\\n uint32 repaymentCycle = uint32(\\n Math.ceilDiv(delta, _paymentCycle)\\n );\\n dueDate_ += (repaymentCycle * _paymentCycle);\\n }\\n }\\n\\n uint32 endOfLoan = _acceptedTimestamp + _loanDuration;\\n //if we are in the last payment cycle, the next due date is the end of loan duration\\n if (dueDate_ > endOfLoan) {\\n dueDate_ = endOfLoan;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x00ad8a0f656c17d963ca519f77a6b17c0435d2a29cc8164dc994a2c06c6cb3ee\",\"license\":\"MIT\"},\"contracts/libraries/WadRayMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n/**\\n * @title WadRayMath library\\n * @author Multiplier Finance\\n * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)\\n */\\nlibrary WadRayMath {\\n using SafeMath for uint256;\\n\\n uint256 internal constant WAD = 1e18;\\n uint256 internal constant halfWAD = WAD / 2;\\n\\n uint256 internal constant RAY = 1e27;\\n uint256 internal constant halfRAY = RAY / 2;\\n\\n uint256 internal constant WAD_RAY_RATIO = 1e9;\\n uint256 internal constant PCT_WAD_RATIO = 1e14;\\n uint256 internal constant PCT_RAY_RATIO = 1e23;\\n\\n function ray() internal pure returns (uint256) {\\n return RAY;\\n }\\n\\n function wad() internal pure returns (uint256) {\\n return WAD;\\n }\\n\\n function halfRay() internal pure returns (uint256) {\\n return halfRAY;\\n }\\n\\n function halfWad() internal pure returns (uint256) {\\n return halfWAD;\\n }\\n\\n function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return halfWAD.add(a.mul(b)).div(WAD);\\n }\\n\\n function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 halfB = b / 2;\\n\\n return halfB.add(a.mul(WAD)).div(b);\\n }\\n\\n function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return halfRAY.add(a.mul(b)).div(RAY);\\n }\\n\\n function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 halfB = b / 2;\\n\\n return halfB.add(a.mul(RAY)).div(b);\\n }\\n\\n function rayToWad(uint256 a) internal pure returns (uint256) {\\n uint256 halfRatio = WAD_RAY_RATIO / 2;\\n\\n return halfRatio.add(a).div(WAD_RAY_RATIO);\\n }\\n\\n function rayToPct(uint256 a) internal pure returns (uint16) {\\n uint256 halfRatio = PCT_RAY_RATIO / 2;\\n\\n uint256 val = halfRatio.add(a).div(PCT_RAY_RATIO);\\n return SafeCast.toUint16(val);\\n }\\n\\n function wadToPct(uint256 a) internal pure returns (uint16) {\\n uint256 halfRatio = PCT_WAD_RATIO / 2;\\n\\n uint256 val = halfRatio.add(a).div(PCT_WAD_RATIO);\\n return SafeCast.toUint16(val);\\n }\\n\\n function wadToRay(uint256 a) internal pure returns (uint256) {\\n return a.mul(WAD_RAY_RATIO);\\n }\\n\\n function pctToRay(uint16 a) internal pure returns (uint256) {\\n return uint256(a).mul(RAY).div(1e4);\\n }\\n\\n function pctToWad(uint16 a) internal pure returns (uint256) {\\n return uint256(a).mul(WAD).div(1e4);\\n }\\n\\n /**\\n * @dev calculates base^duration. The code uses the ModExp precompile\\n * @return z base^duration, in ray\\n */\\n function rayPow(uint256 x, uint256 n) internal pure returns (uint256) {\\n return _pow(x, n, RAY, rayMul);\\n }\\n\\n function wadPow(uint256 x, uint256 n) internal pure returns (uint256) {\\n return _pow(x, n, WAD, wadMul);\\n }\\n\\n function _pow(\\n uint256 x,\\n uint256 n,\\n uint256 p,\\n function(uint256, uint256) internal pure returns (uint256) mul\\n ) internal pure returns (uint256 z) {\\n z = n % 2 != 0 ? x : p;\\n\\n for (n /= 2; n != 0; n /= 2) {\\n x = mul(x, x);\\n\\n if (n % 2 != 0) {\\n z = mul(z, x);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2781319be7a96f56966c601c061849fa94dbf9af5ad80a20c40b879a8d03f14a\",\"license\":\"MIT\"}},\"version\":1}", - "bytecode": "0x6109dc61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80630dcf16581461003a575b600080fd5b61004d6100483660046106d5565b610066565b60405163ffffffff909116815260200160405180910390f35b6000600182600181111561007c5761007c610742565b14156100f857600061009a8763ffffffff168563ffffffff1661019c565b90506100ab8763ffffffff16610223565b6100ba8563ffffffff16610223565b11156100d2576100cb60028261076e565b90506100e0565b6100dd60018261076e565b90505b6100f08763ffffffff168261023d565b91505061016c565b600082600181111561010c5761010c610742565b141561016c5761011c8587610786565b9050600061012a87856107ae565b905063ffffffff81161561016a5760006101508263ffffffff168863ffffffff1661030f565b905061015c87826107d3565b6101669084610786565b9250505b505b60006101788588610786565b90508063ffffffff168263ffffffff161115610192578091505b5095945050505050565b6000818311156101ab57600080fd5b6000806101c36101be6201518087610815565b610349565b5090925090506000806101dc6101be6201518088610815565b509092509050826101ee85600c610829565b826101fa85600c610829565b610204919061076e565b61020e9190610848565b6102189190610848565b979650505050505050565b60006102356101be6201518084610815565b949350505050565b60008080806102526101be6201518088610815565b91945092509050610263858361076e565b9150600c610272600184610848565b61027c9190610815565b610286908461076e565b9250600c610295600184610848565b61029f919061085f565b6102aa90600161076e565b915060006102b884846104bd565b9050808211156102c6578091505b6102d3620151808861085f565b620151806102e2868686610543565b6102ec9190610829565b6102f6919061076e565b94508685101561030557600080fd5b5050505092915050565b6000821561033d5781610323600185610848565b61032d9190610815565b61033890600161076e565b610340565b60005b90505b92915050565b60008080838162253d8c6103608362010bd9610873565b61036a9190610873565b9050600062023ab161037d8360046108b4565b6103879190610939565b905060046103988262023ab16108b4565b6103a3906003610873565b6103ad9190610939565b6103b79083610967565b9150600062164b096103ca846001610873565b6103d690610fa06108b4565b6103e09190610939565b905060046103f0826105b56108b4565b6103fa9190610939565b6104049084610967565b61040f90601f610873565b9250600061098f6104218560506108b4565b61042b9190610939565b90506000605061043d8361098f6108b4565b6104479190610939565b6104519086610967565b905061045e600b83610939565b945061046b85600c6108b4565b610476836002610873565b6104809190610967565b9150848361048f603187610967565b61049a9060646108b4565b6104a49190610873565b6104ae9190610873565b9a919950975095505050505050565b600081600114806104ce5750816003145b806104d95750816005145b806104e45750816007145b806104ef5750816008145b806104fa575081600a145b80610505575081600c145b156105125750601f610343565b816002146105225750601e610343565b61052b83610680565b61053657601c610539565b601d5b60ff169392505050565b60006107b284101561055457600080fd5b838383600062253d8c60046064600c61056e600e88610967565b6105789190610939565b61058488611324610873565b61058e9190610873565b6105989190610939565b6105a39060036108b4565b6105ad9190610939565b600c806105bb600e88610967565b6105c59190610939565b6105d090600c6108b4565b6105db600288610967565b6105e59190610967565b6105f19061016f6108b4565b6105fb9190610939565b6004600c61060a600e89610967565b6106149190610939565b610620896112c0610873565b61062a9190610873565b610636906105b56108b4565b6106409190610939565b61064c617d4b87610967565b6106569190610873565b6106609190610873565b61066a9190610967565b6106749190610967565b98975050505050505050565b600061068d60048361085f565b1580156106a357506106a060648361085f565b15155b8061034357506106b56101908361085f565b1592915050565b803563ffffffff811681146106d057600080fd5b919050565b600080600080600060a086880312156106ed57600080fd5b6106f6866106bc565b9450610704602087016106bc565b9350610712604087016106bc565b9250610720606087016106bc565b915060808601356002811061073457600080fd5b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561078157610781610758565b500190565b600063ffffffff8083168185168083038211156107a5576107a5610758565b01949350505050565b600063ffffffff838116908316818110156107cb576107cb610758565b039392505050565b600063ffffffff808316818516818304811182151516156107f6576107f6610758565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b600082610824576108246107ff565b500490565b600081600019048311821515161561084357610843610758565b500290565b60008282101561085a5761085a610758565b500390565b60008261086e5761086e6107ff565b500690565b600080821280156001600160ff1b038490038513161561089557610895610758565b600160ff1b83900384128116156108ae576108ae610758565b50500190565b60006001600160ff1b03818413828413808216868404861116156108da576108da610758565b600160ff1b60008712828116878305891216156108f9576108f9610758565b6000871292508782058712848416161561091557610915610758565b8785058712818416161561092b5761092b610758565b505050929093029392505050565b600082610948576109486107ff565b600160ff1b82146000198414161561096257610962610758565b500590565b60008083128015600160ff1b85018412161561098557610985610758565b6001600160ff1b03840183138116156109a0576109a0610758565b5050039056fea26469706673582212207ccc3d88c8c7f0eb38a3e9df490b124db988cb2fd272b248bff9fa2eece3b61c64736f6c63430008090033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80630dcf16581461003a575b600080fd5b61004d6100483660046106d5565b610066565b60405163ffffffff909116815260200160405180910390f35b6000600182600181111561007c5761007c610742565b14156100f857600061009a8763ffffffff168563ffffffff1661019c565b90506100ab8763ffffffff16610223565b6100ba8563ffffffff16610223565b11156100d2576100cb60028261076e565b90506100e0565b6100dd60018261076e565b90505b6100f08763ffffffff168261023d565b91505061016c565b600082600181111561010c5761010c610742565b141561016c5761011c8587610786565b9050600061012a87856107ae565b905063ffffffff81161561016a5760006101508263ffffffff168863ffffffff1661030f565b905061015c87826107d3565b6101669084610786565b9250505b505b60006101788588610786565b90508063ffffffff168263ffffffff161115610192578091505b5095945050505050565b6000818311156101ab57600080fd5b6000806101c36101be6201518087610815565b610349565b5090925090506000806101dc6101be6201518088610815565b509092509050826101ee85600c610829565b826101fa85600c610829565b610204919061076e565b61020e9190610848565b6102189190610848565b979650505050505050565b60006102356101be6201518084610815565b949350505050565b60008080806102526101be6201518088610815565b91945092509050610263858361076e565b9150600c610272600184610848565b61027c9190610815565b610286908461076e565b9250600c610295600184610848565b61029f919061085f565b6102aa90600161076e565b915060006102b884846104bd565b9050808211156102c6578091505b6102d3620151808861085f565b620151806102e2868686610543565b6102ec9190610829565b6102f6919061076e565b94508685101561030557600080fd5b5050505092915050565b6000821561033d5781610323600185610848565b61032d9190610815565b61033890600161076e565b610340565b60005b90505b92915050565b60008080838162253d8c6103608362010bd9610873565b61036a9190610873565b9050600062023ab161037d8360046108b4565b6103879190610939565b905060046103988262023ab16108b4565b6103a3906003610873565b6103ad9190610939565b6103b79083610967565b9150600062164b096103ca846001610873565b6103d690610fa06108b4565b6103e09190610939565b905060046103f0826105b56108b4565b6103fa9190610939565b6104049084610967565b61040f90601f610873565b9250600061098f6104218560506108b4565b61042b9190610939565b90506000605061043d8361098f6108b4565b6104479190610939565b6104519086610967565b905061045e600b83610939565b945061046b85600c6108b4565b610476836002610873565b6104809190610967565b9150848361048f603187610967565b61049a9060646108b4565b6104a49190610873565b6104ae9190610873565b9a919950975095505050505050565b600081600114806104ce5750816003145b806104d95750816005145b806104e45750816007145b806104ef5750816008145b806104fa575081600a145b80610505575081600c145b156105125750601f610343565b816002146105225750601e610343565b61052b83610680565b61053657601c610539565b601d5b60ff169392505050565b60006107b284101561055457600080fd5b838383600062253d8c60046064600c61056e600e88610967565b6105789190610939565b61058488611324610873565b61058e9190610873565b6105989190610939565b6105a39060036108b4565b6105ad9190610939565b600c806105bb600e88610967565b6105c59190610939565b6105d090600c6108b4565b6105db600288610967565b6105e59190610967565b6105f19061016f6108b4565b6105fb9190610939565b6004600c61060a600e89610967565b6106149190610939565b610620896112c0610873565b61062a9190610873565b610636906105b56108b4565b6106409190610939565b61064c617d4b87610967565b6106569190610873565b6106609190610873565b61066a9190610967565b6106749190610967565b98975050505050505050565b600061068d60048361085f565b1580156106a357506106a060648361085f565b15155b8061034357506106b56101908361085f565b1592915050565b803563ffffffff811681146106d057600080fd5b919050565b600080600080600060a086880312156106ed57600080fd5b6106f6866106bc565b9450610704602087016106bc565b9350610712604087016106bc565b9250610720606087016106bc565b915060808601356002811061073457600080fd5b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561078157610781610758565b500190565b600063ffffffff8083168185168083038211156107a5576107a5610758565b01949350505050565b600063ffffffff838116908316818110156107cb576107cb610758565b039392505050565b600063ffffffff808316818516818304811182151516156107f6576107f6610758565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b600082610824576108246107ff565b500490565b600081600019048311821515161561084357610843610758565b500290565b60008282101561085a5761085a610758565b500390565b60008261086e5761086e6107ff565b500690565b600080821280156001600160ff1b038490038513161561089557610895610758565b600160ff1b83900384128116156108ae576108ae610758565b50500190565b60006001600160ff1b03818413828413808216868404861116156108da576108da610758565b600160ff1b60008712828116878305891216156108f9576108f9610758565b6000871292508782058712848416161561091557610915610758565b8785058712818416161561092b5761092b610758565b505050929093029392505050565b600082610948576109486107ff565b600160ff1b82146000198414161561096257610962610758565b500590565b60008083128015600160ff1b85018412161561098557610985610758565b6001600160ff1b03840183138116156109a0576109a0610758565b5050039056fea26469706673582212207ccc3d88c8c7f0eb38a3e9df490b124db988cb2fd272b248bff9fa2eece3b61c64736f6c63430008090033", + "numDeployments": 3, + "solcInputHash": "a6b30c70f10157e1bb4295b984117fe9", + "metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_acceptedTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_paymentCycle\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_loanDuration\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_lastRepaidTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"enum PaymentCycleType\",\"name\":\"_bidPaymentCycleType\",\"type\":\"PaymentCycleType\"}],\"name\":\"calculateNextDueDate\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"dueDate_\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libraries/V2Calculations.sol\":\"V2Calculations\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165Upgradeable.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721Upgradeable is IERC165Upgradeable {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x2c0b89cef83f353c6f9488c013d8a5968587ffdd6dfc26aad53774214b97e229\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165Upgradeable {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xc6cef87559d0aeffdf0a99803de655938a7779ec0a3cd5d4383483ad85565a09\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeCast.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\\n * checks.\\n *\\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\\n * easily result in undesired exploitation or bugs, since developers usually\\n * assume that overflows raise errors. `SafeCast` restores this intuition by\\n * reverting the transaction when such an operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n *\\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\\n * all math on `uint256` and `int256` and then downcasting.\\n */\\nlibrary SafeCast {\\n /**\\n * @dev Returns the downcasted uint248 from uint256, reverting on\\n * overflow (when the input is greater than largest uint248).\\n *\\n * Counterpart to Solidity's `uint248` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 248 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint248(uint256 value) internal pure returns (uint248) {\\n require(value <= type(uint248).max, \\\"SafeCast: value doesn't fit in 248 bits\\\");\\n return uint248(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint240 from uint256, reverting on\\n * overflow (when the input is greater than largest uint240).\\n *\\n * Counterpart to Solidity's `uint240` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 240 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint240(uint256 value) internal pure returns (uint240) {\\n require(value <= type(uint240).max, \\\"SafeCast: value doesn't fit in 240 bits\\\");\\n return uint240(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint232 from uint256, reverting on\\n * overflow (when the input is greater than largest uint232).\\n *\\n * Counterpart to Solidity's `uint232` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 232 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint232(uint256 value) internal pure returns (uint232) {\\n require(value <= type(uint232).max, \\\"SafeCast: value doesn't fit in 232 bits\\\");\\n return uint232(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint224 from uint256, reverting on\\n * overflow (when the input is greater than largest uint224).\\n *\\n * Counterpart to Solidity's `uint224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n *\\n * _Available since v4.2._\\n */\\n function toUint224(uint256 value) internal pure returns (uint224) {\\n require(value <= type(uint224).max, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n return uint224(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint216 from uint256, reverting on\\n * overflow (when the input is greater than largest uint216).\\n *\\n * Counterpart to Solidity's `uint216` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 216 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint216(uint256 value) internal pure returns (uint216) {\\n require(value <= type(uint216).max, \\\"SafeCast: value doesn't fit in 216 bits\\\");\\n return uint216(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint208 from uint256, reverting on\\n * overflow (when the input is greater than largest uint208).\\n *\\n * Counterpart to Solidity's `uint208` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 208 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint208(uint256 value) internal pure returns (uint208) {\\n require(value <= type(uint208).max, \\\"SafeCast: value doesn't fit in 208 bits\\\");\\n return uint208(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint200 from uint256, reverting on\\n * overflow (when the input is greater than largest uint200).\\n *\\n * Counterpart to Solidity's `uint200` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 200 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint200(uint256 value) internal pure returns (uint200) {\\n require(value <= type(uint200).max, \\\"SafeCast: value doesn't fit in 200 bits\\\");\\n return uint200(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint192 from uint256, reverting on\\n * overflow (when the input is greater than largest uint192).\\n *\\n * Counterpart to Solidity's `uint192` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 192 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint192(uint256 value) internal pure returns (uint192) {\\n require(value <= type(uint192).max, \\\"SafeCast: value doesn't fit in 192 bits\\\");\\n return uint192(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint184 from uint256, reverting on\\n * overflow (when the input is greater than largest uint184).\\n *\\n * Counterpart to Solidity's `uint184` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 184 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint184(uint256 value) internal pure returns (uint184) {\\n require(value <= type(uint184).max, \\\"SafeCast: value doesn't fit in 184 bits\\\");\\n return uint184(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint176 from uint256, reverting on\\n * overflow (when the input is greater than largest uint176).\\n *\\n * Counterpart to Solidity's `uint176` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 176 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint176(uint256 value) internal pure returns (uint176) {\\n require(value <= type(uint176).max, \\\"SafeCast: value doesn't fit in 176 bits\\\");\\n return uint176(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint168 from uint256, reverting on\\n * overflow (when the input is greater than largest uint168).\\n *\\n * Counterpart to Solidity's `uint168` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 168 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint168(uint256 value) internal pure returns (uint168) {\\n require(value <= type(uint168).max, \\\"SafeCast: value doesn't fit in 168 bits\\\");\\n return uint168(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint160 from uint256, reverting on\\n * overflow (when the input is greater than largest uint160).\\n *\\n * Counterpart to Solidity's `uint160` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 160 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint160(uint256 value) internal pure returns (uint160) {\\n require(value <= type(uint160).max, \\\"SafeCast: value doesn't fit in 160 bits\\\");\\n return uint160(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint152 from uint256, reverting on\\n * overflow (when the input is greater than largest uint152).\\n *\\n * Counterpart to Solidity's `uint152` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 152 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint152(uint256 value) internal pure returns (uint152) {\\n require(value <= type(uint152).max, \\\"SafeCast: value doesn't fit in 152 bits\\\");\\n return uint152(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint144 from uint256, reverting on\\n * overflow (when the input is greater than largest uint144).\\n *\\n * Counterpart to Solidity's `uint144` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 144 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint144(uint256 value) internal pure returns (uint144) {\\n require(value <= type(uint144).max, \\\"SafeCast: value doesn't fit in 144 bits\\\");\\n return uint144(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint136 from uint256, reverting on\\n * overflow (when the input is greater than largest uint136).\\n *\\n * Counterpart to Solidity's `uint136` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 136 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint136(uint256 value) internal pure returns (uint136) {\\n require(value <= type(uint136).max, \\\"SafeCast: value doesn't fit in 136 bits\\\");\\n return uint136(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint128 from uint256, reverting on\\n * overflow (when the input is greater than largest uint128).\\n *\\n * Counterpart to Solidity's `uint128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint128(uint256 value) internal pure returns (uint128) {\\n require(value <= type(uint128).max, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n return uint128(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint120 from uint256, reverting on\\n * overflow (when the input is greater than largest uint120).\\n *\\n * Counterpart to Solidity's `uint120` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 120 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint120(uint256 value) internal pure returns (uint120) {\\n require(value <= type(uint120).max, \\\"SafeCast: value doesn't fit in 120 bits\\\");\\n return uint120(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint112 from uint256, reverting on\\n * overflow (when the input is greater than largest uint112).\\n *\\n * Counterpart to Solidity's `uint112` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 112 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint112(uint256 value) internal pure returns (uint112) {\\n require(value <= type(uint112).max, \\\"SafeCast: value doesn't fit in 112 bits\\\");\\n return uint112(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint104 from uint256, reverting on\\n * overflow (when the input is greater than largest uint104).\\n *\\n * Counterpart to Solidity's `uint104` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 104 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint104(uint256 value) internal pure returns (uint104) {\\n require(value <= type(uint104).max, \\\"SafeCast: value doesn't fit in 104 bits\\\");\\n return uint104(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint96 from uint256, reverting on\\n * overflow (when the input is greater than largest uint96).\\n *\\n * Counterpart to Solidity's `uint96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n *\\n * _Available since v4.2._\\n */\\n function toUint96(uint256 value) internal pure returns (uint96) {\\n require(value <= type(uint96).max, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n return uint96(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint88 from uint256, reverting on\\n * overflow (when the input is greater than largest uint88).\\n *\\n * Counterpart to Solidity's `uint88` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 88 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint88(uint256 value) internal pure returns (uint88) {\\n require(value <= type(uint88).max, \\\"SafeCast: value doesn't fit in 88 bits\\\");\\n return uint88(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint80 from uint256, reverting on\\n * overflow (when the input is greater than largest uint80).\\n *\\n * Counterpart to Solidity's `uint80` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 80 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint80(uint256 value) internal pure returns (uint80) {\\n require(value <= type(uint80).max, \\\"SafeCast: value doesn't fit in 80 bits\\\");\\n return uint80(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint72 from uint256, reverting on\\n * overflow (when the input is greater than largest uint72).\\n *\\n * Counterpart to Solidity's `uint72` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 72 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint72(uint256 value) internal pure returns (uint72) {\\n require(value <= type(uint72).max, \\\"SafeCast: value doesn't fit in 72 bits\\\");\\n return uint72(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint64 from uint256, reverting on\\n * overflow (when the input is greater than largest uint64).\\n *\\n * Counterpart to Solidity's `uint64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint64(uint256 value) internal pure returns (uint64) {\\n require(value <= type(uint64).max, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n return uint64(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint56 from uint256, reverting on\\n * overflow (when the input is greater than largest uint56).\\n *\\n * Counterpart to Solidity's `uint56` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 56 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint56(uint256 value) internal pure returns (uint56) {\\n require(value <= type(uint56).max, \\\"SafeCast: value doesn't fit in 56 bits\\\");\\n return uint56(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint48 from uint256, reverting on\\n * overflow (when the input is greater than largest uint48).\\n *\\n * Counterpart to Solidity's `uint48` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 48 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint48(uint256 value) internal pure returns (uint48) {\\n require(value <= type(uint48).max, \\\"SafeCast: value doesn't fit in 48 bits\\\");\\n return uint48(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint40 from uint256, reverting on\\n * overflow (when the input is greater than largest uint40).\\n *\\n * Counterpart to Solidity's `uint40` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 40 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint40(uint256 value) internal pure returns (uint40) {\\n require(value <= type(uint40).max, \\\"SafeCast: value doesn't fit in 40 bits\\\");\\n return uint40(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint32 from uint256, reverting on\\n * overflow (when the input is greater than largest uint32).\\n *\\n * Counterpart to Solidity's `uint32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint32(uint256 value) internal pure returns (uint32) {\\n require(value <= type(uint32).max, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n return uint32(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint24 from uint256, reverting on\\n * overflow (when the input is greater than largest uint24).\\n *\\n * Counterpart to Solidity's `uint24` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 24 bits\\n *\\n * _Available since v4.7._\\n */\\n function toUint24(uint256 value) internal pure returns (uint24) {\\n require(value <= type(uint24).max, \\\"SafeCast: value doesn't fit in 24 bits\\\");\\n return uint24(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint16 from uint256, reverting on\\n * overflow (when the input is greater than largest uint16).\\n *\\n * Counterpart to Solidity's `uint16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint16(uint256 value) internal pure returns (uint16) {\\n require(value <= type(uint16).max, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n return uint16(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted uint8 from uint256, reverting on\\n * overflow (when the input is greater than largest uint8).\\n *\\n * Counterpart to Solidity's `uint8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits\\n *\\n * _Available since v2.5._\\n */\\n function toUint8(uint256 value) internal pure returns (uint8) {\\n require(value <= type(uint8).max, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n return uint8(value);\\n }\\n\\n /**\\n * @dev Converts a signed int256 into an unsigned uint256.\\n *\\n * Requirements:\\n *\\n * - input must be greater than or equal to 0.\\n *\\n * _Available since v3.0._\\n */\\n function toUint256(int256 value) internal pure returns (uint256) {\\n require(value >= 0, \\\"SafeCast: value must be positive\\\");\\n return uint256(value);\\n }\\n\\n /**\\n * @dev Returns the downcasted int248 from int256, reverting on\\n * overflow (when the input is less than smallest int248 or\\n * greater than largest int248).\\n *\\n * Counterpart to Solidity's `int248` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 248 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\\n downcasted = int248(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 248 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int240 from int256, reverting on\\n * overflow (when the input is less than smallest int240 or\\n * greater than largest int240).\\n *\\n * Counterpart to Solidity's `int240` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 240 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\\n downcasted = int240(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 240 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int232 from int256, reverting on\\n * overflow (when the input is less than smallest int232 or\\n * greater than largest int232).\\n *\\n * Counterpart to Solidity's `int232` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 232 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\\n downcasted = int232(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 232 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int224 from int256, reverting on\\n * overflow (when the input is less than smallest int224 or\\n * greater than largest int224).\\n *\\n * Counterpart to Solidity's `int224` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 224 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\\n downcasted = int224(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 224 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int216 from int256, reverting on\\n * overflow (when the input is less than smallest int216 or\\n * greater than largest int216).\\n *\\n * Counterpart to Solidity's `int216` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 216 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\\n downcasted = int216(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 216 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int208 from int256, reverting on\\n * overflow (when the input is less than smallest int208 or\\n * greater than largest int208).\\n *\\n * Counterpart to Solidity's `int208` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 208 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\\n downcasted = int208(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 208 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int200 from int256, reverting on\\n * overflow (when the input is less than smallest int200 or\\n * greater than largest int200).\\n *\\n * Counterpart to Solidity's `int200` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 200 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\\n downcasted = int200(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 200 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int192 from int256, reverting on\\n * overflow (when the input is less than smallest int192 or\\n * greater than largest int192).\\n *\\n * Counterpart to Solidity's `int192` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 192 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\\n downcasted = int192(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 192 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int184 from int256, reverting on\\n * overflow (when the input is less than smallest int184 or\\n * greater than largest int184).\\n *\\n * Counterpart to Solidity's `int184` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 184 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\\n downcasted = int184(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 184 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int176 from int256, reverting on\\n * overflow (when the input is less than smallest int176 or\\n * greater than largest int176).\\n *\\n * Counterpart to Solidity's `int176` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 176 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\\n downcasted = int176(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 176 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int168 from int256, reverting on\\n * overflow (when the input is less than smallest int168 or\\n * greater than largest int168).\\n *\\n * Counterpart to Solidity's `int168` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 168 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\\n downcasted = int168(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 168 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int160 from int256, reverting on\\n * overflow (when the input is less than smallest int160 or\\n * greater than largest int160).\\n *\\n * Counterpart to Solidity's `int160` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 160 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\\n downcasted = int160(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 160 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int152 from int256, reverting on\\n * overflow (when the input is less than smallest int152 or\\n * greater than largest int152).\\n *\\n * Counterpart to Solidity's `int152` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 152 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\\n downcasted = int152(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 152 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int144 from int256, reverting on\\n * overflow (when the input is less than smallest int144 or\\n * greater than largest int144).\\n *\\n * Counterpart to Solidity's `int144` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 144 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\\n downcasted = int144(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 144 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int136 from int256, reverting on\\n * overflow (when the input is less than smallest int136 or\\n * greater than largest int136).\\n *\\n * Counterpart to Solidity's `int136` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 136 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\\n downcasted = int136(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 136 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int128 from int256, reverting on\\n * overflow (when the input is less than smallest int128 or\\n * greater than largest int128).\\n *\\n * Counterpart to Solidity's `int128` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 128 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\\n downcasted = int128(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 128 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int120 from int256, reverting on\\n * overflow (when the input is less than smallest int120 or\\n * greater than largest int120).\\n *\\n * Counterpart to Solidity's `int120` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 120 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\\n downcasted = int120(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 120 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int112 from int256, reverting on\\n * overflow (when the input is less than smallest int112 or\\n * greater than largest int112).\\n *\\n * Counterpart to Solidity's `int112` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 112 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\\n downcasted = int112(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 112 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int104 from int256, reverting on\\n * overflow (when the input is less than smallest int104 or\\n * greater than largest int104).\\n *\\n * Counterpart to Solidity's `int104` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 104 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\\n downcasted = int104(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 104 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int96 from int256, reverting on\\n * overflow (when the input is less than smallest int96 or\\n * greater than largest int96).\\n *\\n * Counterpart to Solidity's `int96` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 96 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\\n downcasted = int96(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 96 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int88 from int256, reverting on\\n * overflow (when the input is less than smallest int88 or\\n * greater than largest int88).\\n *\\n * Counterpart to Solidity's `int88` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 88 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\\n downcasted = int88(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 88 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int80 from int256, reverting on\\n * overflow (when the input is less than smallest int80 or\\n * greater than largest int80).\\n *\\n * Counterpart to Solidity's `int80` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 80 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\\n downcasted = int80(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 80 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int72 from int256, reverting on\\n * overflow (when the input is less than smallest int72 or\\n * greater than largest int72).\\n *\\n * Counterpart to Solidity's `int72` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 72 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\\n downcasted = int72(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 72 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int64 from int256, reverting on\\n * overflow (when the input is less than smallest int64 or\\n * greater than largest int64).\\n *\\n * Counterpart to Solidity's `int64` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 64 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\\n downcasted = int64(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 64 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int56 from int256, reverting on\\n * overflow (when the input is less than smallest int56 or\\n * greater than largest int56).\\n *\\n * Counterpart to Solidity's `int56` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 56 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\\n downcasted = int56(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 56 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int48 from int256, reverting on\\n * overflow (when the input is less than smallest int48 or\\n * greater than largest int48).\\n *\\n * Counterpart to Solidity's `int48` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 48 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\\n downcasted = int48(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 48 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int40 from int256, reverting on\\n * overflow (when the input is less than smallest int40 or\\n * greater than largest int40).\\n *\\n * Counterpart to Solidity's `int40` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 40 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\\n downcasted = int40(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 40 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int32 from int256, reverting on\\n * overflow (when the input is less than smallest int32 or\\n * greater than largest int32).\\n *\\n * Counterpart to Solidity's `int32` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 32 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\\n downcasted = int32(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 32 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int24 from int256, reverting on\\n * overflow (when the input is less than smallest int24 or\\n * greater than largest int24).\\n *\\n * Counterpart to Solidity's `int24` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 24 bits\\n *\\n * _Available since v4.7._\\n */\\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\\n downcasted = int24(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 24 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int16 from int256, reverting on\\n * overflow (when the input is less than smallest int16 or\\n * greater than largest int16).\\n *\\n * Counterpart to Solidity's `int16` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 16 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\\n downcasted = int16(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 16 bits\\\");\\n }\\n\\n /**\\n * @dev Returns the downcasted int8 from int256, reverting on\\n * overflow (when the input is less than smallest int8 or\\n * greater than largest int8).\\n *\\n * Counterpart to Solidity's `int8` operator.\\n *\\n * Requirements:\\n *\\n * - input must fit into 8 bits\\n *\\n * _Available since v3.1._\\n */\\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\\n downcasted = int8(value);\\n require(downcasted == value, \\\"SafeCast: value doesn't fit in 8 bits\\\");\\n }\\n\\n /**\\n * @dev Converts an unsigned uint256 into a signed int256.\\n *\\n * Requirements:\\n *\\n * - input must be less than or equal to maxInt256.\\n *\\n * _Available since v3.0._\\n */\\n function toInt256(uint256 value) internal pure returns (int256) {\\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\\n require(value <= uint256(type(int256).max), \\\"SafeCast: value doesn't fit in an int256\\\");\\n return int256(value);\\n }\\n}\\n\",\"keccak256\":\"0x52a8cfb0f5239d11b457dcdd1b326992ef672714ca8da71a157255bddd13f3ad\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\\n\\npragma solidity ^0.8.0;\\n\\n// CAUTION\\n// This version of SafeMath should only be used with Solidity 0.8 or later,\\n// because it relies on the compiler's built in overflow checks.\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations.\\n *\\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\\n * now has built in overflow checking.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n uint256 c = a + b;\\n if (c < a) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b > a) return (false, 0);\\n return (true, a - b);\\n }\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) return (true, 0);\\n uint256 c = a * b;\\n if (c / a != b) return (false, 0);\\n return (true, c);\\n }\\n }\\n\\n /**\\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a / b);\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\\n *\\n * _Available since v3.4._\\n */\\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\\n unchecked {\\n if (b == 0) return (false, 0);\\n return (true, a % b);\\n }\\n }\\n\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n *\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a + b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a - b;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n *\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a * b;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator.\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a / b;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a % b;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {trySub}.\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n *\\n * - Subtraction cannot overflow.\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b <= a, errorMessage);\\n return a - b;\\n }\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a / b;\\n }\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * reverting with custom message when dividing by zero.\\n *\\n * CAUTION: This function is deprecated because it requires allocating memory for the error\\n * message unnecessarily. For custom revert reasons use {tryMod}.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n *\\n * - The divisor cannot be zero.\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n unchecked {\\n require(b > 0, errorMessage);\\n return a % b;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0f633a0223d9a1dcccfcf38a64c9de0874dfcbfac0c6941ccf074d63a2ce0e1e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n * // Add the library methods\\n * using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n * // Declare a set state variable\\n * EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n *\\n * [WARNING]\\n * ====\\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\\n * unusable.\\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\\n *\\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\\n * array of EnumerableSet.\\n * ====\\n */\\nlibrary EnumerableSet {\\n // To implement this library for multiple types with as little code\\n // repetition as possible, we write it in terms of a generic Set type with\\n // bytes32 values.\\n // The Set implementation uses private functions, and user-facing\\n // implementations (such as AddressSet) are just wrappers around the\\n // underlying Set.\\n // This means that we can only create new EnumerableSets for types that fit\\n // in bytes32.\\n\\n struct Set {\\n // Storage of set values\\n bytes32[] _values;\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(bytes32 => uint256) _indexes;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function _add(Set storage set, bytes32 value) private returns (bool) {\\n if (!_contains(set, value)) {\\n set._values.push(value);\\n // The value is stored at length-1, but we add 1 to all indexes\\n // and use 0 as a sentinel value\\n set._indexes[value] = set._values.length;\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function _remove(Set storage set, bytes32 value) private returns (bool) {\\n // We read and store the value's index to prevent multiple reads from the same storage slot\\n uint256 valueIndex = set._indexes[value];\\n\\n if (valueIndex != 0) {\\n // Equivalent to contains(set, value)\\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n // the array, and then remove the last element (sometimes called as 'swap and pop').\\n // This modifies the order of the array, as noted in {at}.\\n\\n uint256 toDeleteIndex = valueIndex - 1;\\n uint256 lastIndex = set._values.length - 1;\\n\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set._values[lastIndex];\\n\\n // Move the last value to the index where the value to delete is\\n set._values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\\n }\\n\\n // Delete the slot where the moved value was stored\\n set._values.pop();\\n\\n // Delete the index for the deleted slot\\n delete set._indexes[value];\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n return set._indexes[value] != 0;\\n }\\n\\n /**\\n * @dev Returns the number of values on the set. O(1).\\n */\\n function _length(Set storage set) private view returns (uint256) {\\n return set._values.length;\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n return set._values[index];\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function _values(Set storage set) private view returns (bytes32[] memory) {\\n return set._values;\\n }\\n\\n // Bytes32Set\\n\\n struct Bytes32Set {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _add(set._inner, value);\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n return _remove(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return _contains(set._inner, value);\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return _at(set._inner, index);\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n bytes32[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // AddressSet\\n\\n struct AddressSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n return _add(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n return _remove(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(uint256(uint160(value))));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n return address(uint160(uint256(_at(set._inner, index))));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(AddressSet storage set) internal view returns (address[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n address[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n\\n // UintSet\\n\\n struct UintSet {\\n Set _inner;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n *\\n * Returns true if the value was added to the set, that is if it was not\\n * already present.\\n */\\n function add(UintSet storage set, uint256 value) internal returns (bool) {\\n return _add(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n *\\n * Returns true if the value was removed from the set, that is if it was\\n * present.\\n */\\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n return _remove(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n return _contains(set._inner, bytes32(value));\\n }\\n\\n /**\\n * @dev Returns the number of values in the set. O(1).\\n */\\n function length(UintSet storage set) internal view returns (uint256) {\\n return _length(set._inner);\\n }\\n\\n /**\\n * @dev Returns the value stored at position `index` in the set. O(1).\\n *\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n return uint256(_at(set._inner, index));\\n }\\n\\n /**\\n * @dev Return the entire set in an array\\n *\\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n */\\n function values(UintSet storage set) internal view returns (uint256[] memory) {\\n bytes32[] memory store = _values(set._inner);\\n uint256[] memory result;\\n\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := store\\n }\\n\\n return result;\\n }\\n}\\n\",\"keccak256\":\"0xc3ff3f5c4584e1d9a483ad7ced51ab64523201f4e3d3c65293e4ca8aeb77a961\",\"license\":\"MIT\"},\"contracts/TellerV2Storage.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n// SPDX-License-Identifier: MIT\\n\\nimport { IMarketRegistry_V2 } from \\\"./interfaces/IMarketRegistry_V2.sol\\\";\\nimport \\\"./interfaces/IEscrowVault.sol\\\";\\nimport \\\"./interfaces/IReputationManager.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"./interfaces/ICollateralManagerV1.sol\\\";\\nimport \\\"./interfaces/ICollateralManagerV2.sol\\\";\\nimport { PaymentType, PaymentCycleType } from \\\"./libraries/V2Calculations.sol\\\";\\nimport \\\"./interfaces/ILenderManager.sol\\\";\\n\\nenum BidState {\\n NONEXISTENT,\\n PENDING,\\n CANCELLED,\\n ACCEPTED,\\n PAID,\\n LIQUIDATED,\\n CLOSED\\n}\\n\\n/**\\n * @notice Represents a total amount for a payment.\\n * @param principal Amount that counts towards the principal.\\n * @param interest Amount that counts toward interest.\\n */\\nstruct Payment {\\n uint256 principal;\\n uint256 interest;\\n}\\n\\n/**\\n * @notice Details about a loan request.\\n * @param borrower Account address who is requesting a loan.\\n * @param receiver Account address who will receive the loan amount.\\n * @param lender Account address who accepted and funded the loan request.\\n * @param marketplaceId ID of the marketplace the bid was submitted to.\\n * @param metadataURI ID of off chain metadata to find additional information of the loan request.\\n * @param loanDetails Struct of the specific loan details.\\n * @param terms Struct of the loan request terms.\\n * @param state Represents the current state of the loan.\\n */\\nstruct Bid {\\n address borrower;\\n address receiver;\\n address lender; // if this is the LenderManager address, we use that .owner() as source of truth\\n uint256 marketplaceId;\\n bytes32 _metadataURI; // DEPRECATED\\n LoanDetails loanDetails;\\n Terms terms;\\n BidState state;\\n PaymentType paymentType; // DEPRECATED\\n}\\n\\n/**\\n * @notice Details about the loan.\\n * @param lendingToken The token address for the loan.\\n * @param principal The amount of tokens initially lent out.\\n * @param totalRepaid Payment struct that represents the total principal and interest amount repaid.\\n * @param timestamp Timestamp, in seconds, of when the bid was submitted by the borrower.\\n * @param acceptedTimestamp Timestamp, in seconds, of when the bid was accepted by the lender.\\n * @param lastRepaidTimestamp Timestamp, in seconds, of when the last payment was made\\n * @param loanDuration The duration of the loan.\\n */\\nstruct LoanDetails {\\n IERC20 lendingToken;\\n uint256 principal;\\n Payment totalRepaid;\\n uint32 timestamp;\\n uint32 acceptedTimestamp;\\n uint32 lastRepaidTimestamp;\\n uint32 loanDuration;\\n}\\n\\n/**\\n * @notice Information on the terms of a loan request\\n * @param paymentCycleAmount Value of tokens expected to be repaid every payment cycle.\\n * @param paymentCycle Duration, in seconds, of how often a payment must be made.\\n * @param APR Annual percentage rating to be applied on repayments. (10000 == 100%)\\n */\\nstruct Terms {\\n uint256 paymentCycleAmount;\\n uint32 paymentCycle; // DEPRECATED\\n uint16 APR;\\n}\\n\\nabstract contract TellerV2Storage_G0 {\\n /** Storage Variables */\\n\\n // Current number of bids.\\n uint256 public nextBidId;\\n\\n // Mapping of bidId to bid information.\\n mapping(uint256 => Bid) public bids;\\n\\n // Mapping of borrowers to borrower requests.\\n mapping(address => uint256[]) public borrowerBids; //DEPRECATED\\n\\n // Mapping of volume filled by lenders.\\n mapping(address => uint256) public __lenderVolumeFilled; // DEPRECATED\\n\\n // Volume filled by all lenders.\\n uint256 public __totalVolumeFilled; // DEPRECATED\\n\\n // List of allowed lending tokens\\n EnumerableSet.AddressSet internal __lendingTokensSet; // DEPRECATED\\n\\n IMarketRegistry_V2 public marketRegistry;\\n IReputationManager public reputationManager;\\n\\n // Mapping of borrowers to borrower requests.\\n mapping(address => EnumerableSet.UintSet) internal _borrowerBidsActive; //DEPRECATED\\n\\n mapping(uint256 => uint32) public bidDefaultDuration; //DEPRECATED\\n mapping(uint256 => uint32) public bidExpirationTime; //DEPRECATED\\n\\n // Mapping of volume filled by lenders.\\n // Asset address => Lender address => Volume amount\\n mapping(address => mapping(address => uint256)) public lenderVolumeFilled;\\n\\n // Volume filled by all lenders.\\n // Asset address => Volume amount\\n mapping(address => uint256) public totalVolumeFilled;\\n\\n uint256 public version;\\n\\n // Mapping of metadataURIs by bidIds.\\n // Bid Id => metadataURI string\\n mapping(uint256 => string) public uris; //DEPRECATED\\n}\\n\\nabstract contract TellerV2Storage_G1 is TellerV2Storage_G0 {\\n // market ID => trusted forwarder\\n mapping(uint256 => address) internal _trustedMarketForwarders;\\n // trusted forwarder => set of pre-approved senders\\n mapping(address => EnumerableSet.AddressSet)\\n internal _approvedForwarderSenders;\\n}\\n\\nabstract contract TellerV2Storage_G2 is TellerV2Storage_G1 {\\n address public lenderCommitmentForwarder; //deprecated\\n}\\n\\nabstract contract TellerV2Storage_G3 is TellerV2Storage_G2 {\\n ICollateralManagerV1 public collateralManagerV1;\\n}\\n\\nabstract contract TellerV2Storage_G4 is TellerV2Storage_G3 {\\n // Address of the lender manager contract\\n ILenderManager public lenderManager;\\n // BidId to payment cycle type (custom or monthly)\\n mapping(uint256 => PaymentCycleType) public bidPaymentCycleType; //DEPRECATED\\n}\\n\\nabstract contract TellerV2Storage_G5 is TellerV2Storage_G4 {\\n // Address of the lender manager contract\\n IEscrowVault public escrowVault;\\n}\\n\\nabstract contract TellerV2Storage_G6 is TellerV2Storage_G5 {\\n ICollateralManagerV2 public collateralManagerV2;\\n mapping(uint256 => address) public collateralManagerForBid; //if this is zero, that means v1\\n}\\n\\nabstract contract TellerV2Storage_G7 is TellerV2Storage_G6 {\\n // If this is zero for a bid, the bid will use the values in the bid struct / bidDefaultDuration / bidExpirationTime\\n //need internal fns to do this if/then\\n mapping(uint256 => bytes32) public bidMarketTermsId;\\n}\\n\\nabstract contract TellerV2Storage is TellerV2Storage_G7 {}\\n\",\"keccak256\":\"0x0a7463a94668cbc217f22216932ba84fd370279b8d72f0e4a447b68a40e730a1\",\"license\":\"MIT\"},\"contracts/bundle/interfaces/ICollateralBundle.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity ^0.8.0;\\n\\n/**\\n * Group together arbitrary ERC20, ERC721 and ERC1155 tokens into a single bundle.\\n *\\n * The `Token` struct is a generic type that can describe any ERC20, ERC721 or ERC1155 token.\\n * The `Bundle` struct is a data structure to track a group/bundle of multiple assets i.e. ERC20,\\n * ERC721 and ERC1155 tokens, each described as a `Token`.\\n *\\n * Expressing tokens as the `Token` type, and grouping them as a `Bundle` allows for writing generic\\n * logic to handle any ERC20, ERC721 or ERC1155 tokens.\\n */\\n\\n/// @notice The type of assets that can be bundled.\\nenum CollateralType {\\n ERC20,\\n ERC721,\\n ERC1155\\n}\\n\\n/**\\n * @notice A generic interface to describe any ERC20, ERC721 or ERC1155 token.\\n * @param _collateralType The token type (ERC20 / ERC721 / ERC1155) of the asset.\\n * @param _amount The amount of the asset, if the asset is an ERC20 / ERC1155 fungible token.\\n * @param _tokenId The token Id of the asset, if the asset is an ERC721 / ERC1155 NFT.\\n * @param _collateralAddress The contract address of the asset.\\n *\\n */\\nstruct Collateral {\\n CollateralType _collateralType;\\n uint256 _amount;\\n uint256 _tokenId;\\n address _collateralAddress;\\n}\\n\\ninterface ICollateralBundle {\\n /**\\n * @notice An internal data structure to track a group / bundle of multiple assets i.e. `Token`s.\\n *\\n * @param count The total number of assets i.e. `Collateral` in a bundle.\\n * @param collaterals Mapping from a UID -> to a unique asset i.e. `Collateral` in the bundle.\\n */\\n struct CollateralBundleInfo {\\n uint256 count;\\n mapping(uint256 => Collateral) collaterals;\\n }\\n}\\n\",\"keccak256\":\"0x8f229fe47e8e7c746e6d97c466832c91646122a50cf8bff4f7f9a7e16b174791\",\"license\":\"Apache-2.0\"},\"contracts/interfaces/ICollateralManager.sol\":{\"content\":\"// SPDX-Licence-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport { Collateral } from \\\"../bundle/interfaces/ICollateralBundle.sol\\\";\\n\\ninterface ICollateralManager {\\n /**\\n * @notice Checks the validity of a borrower's collateral balance.\\n * @param _bidId The id of the associated bid.\\n * @param _collateralInfo Additional information about the collateral asset.\\n * @return validation_ Boolean indicating if the collateral balance was validated.\\n */\\n function commitCollateral(\\n uint256 _bidId,\\n Collateral[] calldata _collateralInfo\\n ) external returns (bool validation_);\\n\\n /**\\n * @notice Gets the collateral info for a given bid id.\\n * @param _bidId The bidId to return the collateral info for.\\n * @return The stored collateral info.\\n */\\n function getCollateralInfo(uint256 _bidId)\\n external\\n view\\n returns (Collateral[] memory);\\n\\n function getCollateralAmount(uint256 _bidId, address collateralAssetAddress)\\n external\\n view\\n returns (uint256 _amount);\\n\\n /**\\n * @notice Withdraws deposited collateral from the created escrow of a bid.\\n * @param _bidId The id of the bid to withdraw collateral for.\\n */\\n function withdraw(uint256 _bidId) external;\\n\\n /**\\n * @notice Sends the deposited collateral to a lender of a bid.\\n * @notice Can only be called by the protocol.\\n * @param _bidId The id of the liquidated bid.\\n */\\n function lenderClaimCollateral(uint256 _bidId) external;\\n\\n /**\\n * @notice Sends the deposited collateral to a liquidator of a bid.\\n * @notice Can only be called by the protocol.\\n * @param _bidId The id of the liquidated bid.\\n * @param _liquidatorAddress The address of the liquidator to send the collateral to.\\n */\\n function liquidateCollateral(uint256 _bidId, address _liquidatorAddress)\\n external;\\n}\\n\",\"keccak256\":\"0xebefcacd557a58e56e440ca274a0c7ec1d57b4bc2b0d62007d5fbd041cb0aa48\"},\"contracts/interfaces/ICollateralManagerV1.sol\":{\"content\":\"// SPDX-Licence-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\n//import { Collateral } from \\\"./escrow/ICollateralEscrowV1.sol\\\";\\n\\nimport { Collateral } from \\\"../bundle/interfaces/ICollateralBundle.sol\\\";\\n\\nimport \\\"./ICollateralManager.sol\\\";\\n\\ninterface ICollateralManagerV1 is ICollateralManager {\\n function checkBalances(\\n address _borrowerAddress,\\n Collateral[] calldata _collateralInfo\\n ) external returns (bool validated_, bool[] memory checks_);\\n\\n /**\\n * @notice Deploys a new collateral escrow.\\n * @param _bidId The associated bidId of the collateral escrow.\\n */\\n function deployAndDeposit(uint256 _bidId) external;\\n\\n /**\\n * @notice Gets the address of a deployed escrow.\\n * @notice _bidId The bidId to return the escrow for.\\n * @return The address of the escrow.\\n */\\n function getEscrow(uint256 _bidId) external view returns (address);\\n\\n /**\\n * @notice Re-checks the validity of a borrower's collateral balance committed to a bid.\\n * @param _bidId The id of the associated bid.\\n * @return validation_ Boolean indicating if the collateral balance was validated.\\n */\\n function revalidateCollateral(uint256 _bidId) external returns (bool);\\n}\\n\",\"keccak256\":\"0xc4abc552dd8fb1d7b6f0be2947bb82586806a6f53112907eb391b6713b0290eb\"},\"contracts/interfaces/ICollateralManagerV2.sol\":{\"content\":\"// SPDX-Licence-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./ICollateralManager.sol\\\";\\n\\n//use TokenBundle\\n/*\\nenum CollateralType {\\n ERC20,\\n ERC721,\\n ERC1155\\n}\\n\\nstruct Collateral {\\n CollateralType _collateralType;\\n uint256 _amount;\\n uint256 _tokenId;\\n address _collateralAddress;\\n}*/\\n\\nimport { Collateral } from \\\"../bundle/interfaces/ICollateralBundle.sol\\\";\\n\\ninterface ICollateralManagerV2 is ICollateralManager {\\n /**\\n * @notice Deploys a new collateral escrow.\\n * @param _bidId The associated bidId of the collateral escrow.\\n */\\n function depositCollateral(uint256 _bidId) external;\\n\\n /**\\n * @notice Gets the address of a deployed escrow.\\n * @notice _bidId The bidId to return the escrow for.\\n * @return The address of the escrow.\\n */\\n // function getEscrow(uint256 _bidId) external view returns (address);\\n\\n /**\\n * @notice Gets the collateral info for a given bid id.\\n * @param _bidId The bidId to return the collateral info for.\\n * @return The stored collateral info.\\n */\\n function getCollateralInfo(uint256 _bidId)\\n external\\n view\\n returns (Collateral[] memory);\\n\\n function getCollateralAmount(uint256 _bidId, address collateralAssetAddress)\\n external\\n view\\n returns (uint256 _amount);\\n}\\n\",\"keccak256\":\"0xca255d1c590b4bfbbcdb46bb1d8efcd52a63feb404a7880d0142566df86ee5f2\"},\"contracts/interfaces/IEscrowVault.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\ninterface IEscrowVault {\\n /**\\n * @notice Deposit tokens on behalf of another account\\n * @param account The address of the account\\n * @param token The address of the token\\n * @param amount The amount to increase the balance\\n */\\n function deposit(address account, address token, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0x8c95f089fb12f263e98b26c0ce9983a6814736c9ec8a6de603b397fd64c29a9a\",\"license\":\"MIT\"},\"contracts/interfaces/ILenderManager.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n\\n// SPDX-License-Identifier: MIT\\nimport \\\"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\\\";\\n\\nabstract contract ILenderManager is IERC721Upgradeable {\\n /**\\n * @notice Registers a new active lender for a loan, minting the nft.\\n * @param _bidId The id for the loan to set.\\n * @param _newLender The address of the new active lender.\\n */\\n function registerLoan(uint256 _bidId, address _newLender) external virtual;\\n}\\n\",\"keccak256\":\"0xceb1ea2ef4c6e2ad7986db84de49c959e8d59844563d27daca5b8d78b732a8f7\",\"license\":\"MIT\"},\"contracts/interfaces/IMarketRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport { PaymentType, PaymentCycleType } from \\\"../libraries/V2Calculations.sol\\\";\\n\\n\\ninterface IMarketRegistry {\\n function isMarketOpen(uint256 _marketId) external view returns (bool);\\n\\n function isMarketClosed(uint256 _marketId) external view returns (bool);\\n\\n function getMarketOwner(uint256 _marketId) external view returns (address);\\n\\n function closeMarket(uint256 _marketId) external;\\n\\n function getMarketFeeRecipient(uint256 _marketId)\\n external\\n view\\n returns (address);\\n\\n function getMarketURI(uint256 _marketId)\\n external\\n view\\n returns (string memory);\\n\\n \\n\\n function getPaymentDefaultDuration(uint256 _marketId)\\n external\\n view\\n returns (uint32);\\n\\n function getBidExpirationTime(uint256 _marketId)\\n external\\n view\\n returns (uint32);\\n\\n function getPaymentType(uint256 _marketId)\\n external\\n view\\n returns (PaymentType);\\n\\n\\n function getMarketplaceFee(uint256 _marketId)\\n external\\n view\\n returns (uint16);\\n\\n function isVerifiedBorrower(uint256 _marketId, address _borrower)\\n external\\n view\\n returns (bool, bytes32);\\n\\n function isVerifiedLender(uint256 _marketId, address _lender)\\n external\\n view\\n returns (bool, bytes32);\\n\\n\\n}\\n\",\"keccak256\":\"0x59e651fddcbdeb236a51718d7d1d67a2a20aa9e5e520f9ddf2b19a976431181b\",\"license\":\"MIT\"},\"contracts/interfaces/IMarketRegistry_V2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\nimport { PaymentType, PaymentCycleType } from \\\"../libraries/V2Calculations.sol\\\";\\n\\nimport { IMarketRegistry } from \\\"./IMarketRegistry.sol\\\";\\n\\ninterface IMarketRegistry_V2 is IMarketRegistry {\\n struct MarketplaceTerms {\\n uint16 marketplaceFeePercent; // 10000 is 100%\\n PaymentType paymentType;\\n PaymentCycleType paymentCycleType;\\n uint32 paymentCycleDuration; // unix time (seconds)\\n uint32 paymentDefaultDuration; //unix time\\n uint32 bidExpirationTime; //unix time\\n address feeRecipient;\\n }\\n\\n \\n function getMarketTermsForLending(bytes32 _marketTermsId)\\n external\\n view\\n returns (uint32, PaymentCycleType, PaymentType, uint32, uint32);\\n\\n function getMarketFeeTerms(bytes32 _marketTermsId)\\n external\\n view\\n returns (address, uint16);\\n\\n function getBidExpirationTimeForTerms(bytes32 _marketTermsId)\\n external\\n view\\n returns (uint32);\\n\\n function getPaymentDefaultDurationForTerms(bytes32 _marketTermsId)\\n external\\n view\\n returns (uint32);\\n\\n function getPaymentTypeForTerms(bytes32 _marketTermsId)\\n external\\n view\\n returns (PaymentType);\\n\\n function getPaymentCycleTypeForTerms(bytes32 _marketTermsId)\\n external\\n view\\n returns (PaymentCycleType);\\n\\n function getPaymentCycleDurationForTerms(bytes32 _marketTermsId)\\n external\\n view\\n returns (uint32);\\n\\n function getPaymentCycleType(uint256 _marketId)\\n external\\n view\\n returns (PaymentCycleType);\\n\\n function getPaymentCycleDuration(uint256 _marketId)\\n external\\n view\\n returns (uint32);\\n\\n function createMarket(\\n address _initialOwner,\\n bool _requireLenderAttestation,\\n bool _requireBorrowerAttestation,\\n string calldata _uri,\\n MarketplaceTerms memory _marketTermsParams\\n ) external returns (uint256 marketId_, bytes32 marketTerms_);\\n\\n \\n\\n function getCurrentTermsForMarket(uint256 _marketId)\\n external\\n view\\n returns (bytes32);\\n}\\n\",\"keccak256\":\"0x1d53814d70fd1a60455442ce2757d8cd8bdd376469adff2b5eb9d1897f6e2020\",\"license\":\"MIT\"},\"contracts/interfaces/IReputationManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum RepMark {\\n Good,\\n Delinquent,\\n Default\\n}\\n\\ninterface IReputationManager {\\n function initialize(address protocolAddress) external;\\n\\n function getDelinquentLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function getDefaultedLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function getCurrentDelinquentLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n function getCurrentDefaultLoanIds(address _account)\\n external\\n returns (uint256[] memory);\\n\\n // function updateAccountReputation(address _account) external;\\n\\n function updateAccountReputation(address _account, uint256 _bidId)\\n external\\n returns (RepMark);\\n}\\n\",\"keccak256\":\"0xf76d1c1d165c07d693a39995e95dd408defdbc0acdc12e8ead076dcc351f5d7a\",\"license\":\"MIT\"},\"contracts/libraries/DateTimeLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.6.0 <0.9.0;\\n\\n// ----------------------------------------------------------------------------\\n// BokkyPooBah's DateTime Library v1.01\\n//\\n// A gas-efficient Solidity date and time library\\n//\\n// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary\\n//\\n// Tested date range 1970/01/01 to 2345/12/31\\n//\\n// Conventions:\\n// Unit | Range | Notes\\n// :-------- |:-------------:|:-----\\n// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC\\n// year | 1970 ... 2345 |\\n// month | 1 ... 12 |\\n// day | 1 ... 31 |\\n// hour | 0 ... 23 |\\n// minute | 0 ... 59 |\\n// second | 0 ... 59 |\\n// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday\\n//\\n//\\n// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.\\n// ----------------------------------------------------------------------------\\n\\nlibrary BokkyPooBahsDateTimeLibrary {\\n uint constant SECONDS_PER_DAY = 24 * 60 * 60;\\n uint constant SECONDS_PER_HOUR = 60 * 60;\\n uint constant SECONDS_PER_MINUTE = 60;\\n int constant OFFSET19700101 = 2440588;\\n\\n uint constant DOW_MON = 1;\\n uint constant DOW_TUE = 2;\\n uint constant DOW_WED = 3;\\n uint constant DOW_THU = 4;\\n uint constant DOW_FRI = 5;\\n uint constant DOW_SAT = 6;\\n uint constant DOW_SUN = 7;\\n\\n // ------------------------------------------------------------------------\\n // Calculate the number of days from 1970/01/01 to year/month/day using\\n // the date conversion algorithm from\\n // https://aa.usno.navy.mil/faq/JD_formula.html\\n // and subtracting the offset 2440588 so that 1970/01/01 is day 0\\n //\\n // days = day\\n // - 32075\\n // + 1461 * (year + 4800 + (month - 14) / 12) / 4\\n // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12\\n // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4\\n // - offset\\n // ------------------------------------------------------------------------\\n function _daysFromDate(uint year, uint month, uint day)\\n internal\\n pure\\n returns (uint _days)\\n {\\n require(year >= 1970);\\n int _year = int(year);\\n int _month = int(month);\\n int _day = int(day);\\n\\n int __days = _day -\\n 32075 +\\n (1461 * (_year + 4800 + (_month - 14) / 12)) /\\n 4 +\\n (367 * (_month - 2 - ((_month - 14) / 12) * 12)) /\\n 12 -\\n (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) /\\n 4 -\\n OFFSET19700101;\\n\\n _days = uint(__days);\\n }\\n\\n // ------------------------------------------------------------------------\\n // Calculate year/month/day from the number of days since 1970/01/01 using\\n // the date conversion algorithm from\\n // http://aa.usno.navy.mil/faq/docs/JD_Formula.php\\n // and adding the offset 2440588 so that 1970/01/01 is day 0\\n //\\n // int L = days + 68569 + offset\\n // int N = 4 * L / 146097\\n // L = L - (146097 * N + 3) / 4\\n // year = 4000 * (L + 1) / 1461001\\n // L = L - 1461 * year / 4 + 31\\n // month = 80 * L / 2447\\n // dd = L - 2447 * month / 80\\n // L = month / 11\\n // month = month + 2 - 12 * L\\n // year = 100 * (N - 49) + year + L\\n // ------------------------------------------------------------------------\\n function _daysToDate(uint _days)\\n internal\\n pure\\n returns (uint year, uint month, uint day)\\n {\\n int __days = int(_days);\\n\\n int L = __days + 68569 + OFFSET19700101;\\n int N = (4 * L) / 146097;\\n L = L - (146097 * N + 3) / 4;\\n int _year = (4000 * (L + 1)) / 1461001;\\n L = L - (1461 * _year) / 4 + 31;\\n int _month = (80 * L) / 2447;\\n int _day = L - (2447 * _month) / 80;\\n L = _month / 11;\\n _month = _month + 2 - 12 * L;\\n _year = 100 * (N - 49) + _year + L;\\n\\n year = uint(_year);\\n month = uint(_month);\\n day = uint(_day);\\n }\\n\\n function timestampFromDate(uint year, uint month, uint day)\\n internal\\n pure\\n returns (uint timestamp)\\n {\\n timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;\\n }\\n\\n function timestampFromDateTime(\\n uint year,\\n uint month,\\n uint day,\\n uint hour,\\n uint minute,\\n uint second\\n ) internal pure returns (uint timestamp) {\\n timestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n hour *\\n SECONDS_PER_HOUR +\\n minute *\\n SECONDS_PER_MINUTE +\\n second;\\n }\\n\\n function timestampToDate(uint timestamp)\\n internal\\n pure\\n returns (uint year, uint month, uint day)\\n {\\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function timestampToDateTime(uint timestamp)\\n internal\\n pure\\n returns (\\n uint year,\\n uint month,\\n uint day,\\n uint hour,\\n uint minute,\\n uint second\\n )\\n {\\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n uint secs = timestamp % SECONDS_PER_DAY;\\n hour = secs / SECONDS_PER_HOUR;\\n secs = secs % SECONDS_PER_HOUR;\\n minute = secs / SECONDS_PER_MINUTE;\\n second = secs % SECONDS_PER_MINUTE;\\n }\\n\\n function isValidDate(uint year, uint month, uint day)\\n internal\\n pure\\n returns (bool valid)\\n {\\n if (year >= 1970 && month > 0 && month <= 12) {\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > 0 && day <= daysInMonth) {\\n valid = true;\\n }\\n }\\n }\\n\\n function isValidDateTime(\\n uint year,\\n uint month,\\n uint day,\\n uint hour,\\n uint minute,\\n uint second\\n ) internal pure returns (bool valid) {\\n if (isValidDate(year, month, day)) {\\n if (hour < 24 && minute < 60 && second < 60) {\\n valid = true;\\n }\\n }\\n }\\n\\n function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {\\n (uint year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n leapYear = _isLeapYear(year);\\n }\\n\\n function _isLeapYear(uint year) internal pure returns (bool leapYear) {\\n leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);\\n }\\n\\n function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {\\n weekDay = getDayOfWeek(timestamp) <= DOW_FRI;\\n }\\n\\n function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {\\n weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;\\n }\\n\\n function getDaysInMonth(uint timestamp)\\n internal\\n pure\\n returns (uint daysInMonth)\\n {\\n (uint year, uint month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n daysInMonth = _getDaysInMonth(year, month);\\n }\\n\\n function _getDaysInMonth(uint year, uint month)\\n internal\\n pure\\n returns (uint daysInMonth)\\n {\\n if (\\n month == 1 ||\\n month == 3 ||\\n month == 5 ||\\n month == 7 ||\\n month == 8 ||\\n month == 10 ||\\n month == 12\\n ) {\\n daysInMonth = 31;\\n } else if (month != 2) {\\n daysInMonth = 30;\\n } else {\\n daysInMonth = _isLeapYear(year) ? 29 : 28;\\n }\\n }\\n\\n // 1 = Monday, 7 = Sunday\\n function getDayOfWeek(uint timestamp)\\n internal\\n pure\\n returns (uint dayOfWeek)\\n {\\n uint _days = timestamp / SECONDS_PER_DAY;\\n dayOfWeek = ((_days + 3) % 7) + 1;\\n }\\n\\n function getYear(uint timestamp) internal pure returns (uint year) {\\n (year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function getMonth(uint timestamp) internal pure returns (uint month) {\\n (, month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function getDay(uint timestamp) internal pure returns (uint day) {\\n (, , day) = _daysToDate(timestamp / SECONDS_PER_DAY);\\n }\\n\\n function getHour(uint timestamp) internal pure returns (uint hour) {\\n uint secs = timestamp % SECONDS_PER_DAY;\\n hour = secs / SECONDS_PER_HOUR;\\n }\\n\\n function getMinute(uint timestamp) internal pure returns (uint minute) {\\n uint secs = timestamp % SECONDS_PER_HOUR;\\n minute = secs / SECONDS_PER_MINUTE;\\n }\\n\\n function getSecond(uint timestamp) internal pure returns (uint second) {\\n second = timestamp % SECONDS_PER_MINUTE;\\n }\\n\\n function addYears(uint timestamp, uint _years)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n year += _years;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addMonths(uint timestamp, uint _months)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n month += _months;\\n year += (month - 1) / 12;\\n month = ((month - 1) % 12) + 1;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addDays(uint timestamp, uint _days)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _days * SECONDS_PER_DAY;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addHours(uint timestamp, uint _hours)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addMinutes(uint timestamp, uint _minutes)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function addSeconds(uint timestamp, uint _seconds)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp + _seconds;\\n require(newTimestamp >= timestamp);\\n }\\n\\n function subYears(uint timestamp, uint _years)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n year -= _years;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subMonths(uint timestamp, uint _months)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n (uint year, uint month, uint day) = _daysToDate(\\n timestamp / SECONDS_PER_DAY\\n );\\n uint yearMonth = year * 12 + (month - 1) - _months;\\n year = yearMonth / 12;\\n month = (yearMonth % 12) + 1;\\n uint daysInMonth = _getDaysInMonth(year, month);\\n if (day > daysInMonth) {\\n day = daysInMonth;\\n }\\n newTimestamp =\\n _daysFromDate(year, month, day) *\\n SECONDS_PER_DAY +\\n (timestamp % SECONDS_PER_DAY);\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subDays(uint timestamp, uint _days)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _days * SECONDS_PER_DAY;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subHours(uint timestamp, uint _hours)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subMinutes(uint timestamp, uint _minutes)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function subSeconds(uint timestamp, uint _seconds)\\n internal\\n pure\\n returns (uint newTimestamp)\\n {\\n newTimestamp = timestamp - _seconds;\\n require(newTimestamp <= timestamp);\\n }\\n\\n function diffYears(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _years)\\n {\\n require(fromTimestamp <= toTimestamp);\\n (uint fromYear, , ) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);\\n (uint toYear, , ) = _daysToDate(toTimestamp / SECONDS_PER_DAY);\\n _years = toYear - fromYear;\\n }\\n\\n function diffMonths(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _months)\\n {\\n require(fromTimestamp <= toTimestamp);\\n (uint fromYear, uint fromMonth, ) = _daysToDate(\\n fromTimestamp / SECONDS_PER_DAY\\n );\\n (uint toYear, uint toMonth, ) = _daysToDate(\\n toTimestamp / SECONDS_PER_DAY\\n );\\n _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;\\n }\\n\\n function diffDays(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _days)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;\\n }\\n\\n function diffHours(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _hours)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;\\n }\\n\\n function diffMinutes(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _minutes)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;\\n }\\n\\n function diffSeconds(uint fromTimestamp, uint toTimestamp)\\n internal\\n pure\\n returns (uint _seconds)\\n {\\n require(fromTimestamp <= toTimestamp);\\n _seconds = toTimestamp - fromTimestamp;\\n }\\n}\\n\",\"keccak256\":\"0xf194df8ea9946a5bb3300223629b7e4959c1f20bacba27b3dc5f6dd2a160147a\",\"license\":\"MIT\"},\"contracts/libraries/NumbersLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n// Libraries\\nimport { SafeCast } from \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\nimport { Math } from \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\nimport \\\"./WadRayMath.sol\\\";\\n\\n/**\\n * @dev Utility library for uint256 numbers\\n *\\n * @author develop@teller.finance\\n */\\nlibrary NumbersLib {\\n using WadRayMath for uint256;\\n\\n /**\\n * @dev It represents 100% with 2 decimal places.\\n */\\n uint16 internal constant PCT_100 = 10000;\\n\\n function percentFactor(uint256 decimals) internal pure returns (uint256) {\\n return 100 * (10**decimals);\\n }\\n\\n /**\\n * @notice Returns a percentage value of a number.\\n * @param self The number to get a percentage of.\\n * @param percentage The percentage value to calculate with 2 decimal places (10000 = 100%).\\n */\\n function percent(uint256 self, uint16 percentage)\\n internal\\n pure\\n returns (uint256)\\n {\\n return percent(self, percentage, 2);\\n }\\n\\n /**\\n * @notice Returns a percentage value of a number.\\n * @param self The number to get a percentage of.\\n * @param percentage The percentage value to calculate with.\\n * @param decimals The number of decimals the percentage value is in.\\n */\\n function percent(uint256 self, uint256 percentage, uint256 decimals)\\n internal\\n pure\\n returns (uint256)\\n {\\n return (self * percentage) / percentFactor(decimals);\\n }\\n\\n /**\\n * @notice it returns the absolute number of a specified parameter\\n * @param self the number to be returned in it's absolute\\n * @return the absolute number\\n */\\n function abs(int256 self) internal pure returns (uint256) {\\n return self >= 0 ? uint256(self) : uint256(-1 * self);\\n }\\n\\n /**\\n * @notice Returns a ratio percentage of {num1} to {num2}.\\n * @dev Returned value is type uint16.\\n * @param num1 The number used to get the ratio for.\\n * @param num2 The number used to get the ratio from.\\n * @return Ratio percentage with 2 decimal places (10000 = 100%).\\n */\\n function ratioOf(uint256 num1, uint256 num2)\\n internal\\n pure\\n returns (uint16)\\n {\\n return SafeCast.toUint16(ratioOf(num1, num2, 2));\\n }\\n\\n /**\\n * @notice Returns a ratio percentage of {num1} to {num2}.\\n * @param num1 The number used to get the ratio for.\\n * @param num2 The number used to get the ratio from.\\n * @param decimals The number of decimals the percentage value is returned in.\\n * @return Ratio percentage value.\\n */\\n function ratioOf(uint256 num1, uint256 num2, uint256 decimals)\\n internal\\n pure\\n returns (uint256)\\n {\\n if (num2 == 0) return 0;\\n return (num1 * percentFactor(decimals)) / num2;\\n }\\n\\n /**\\n * @notice Calculates the payment amount for a cycle duration.\\n * The formula is calculated based on the standard Estimated Monthly Installment (https://en.wikipedia.org/wiki/Equated_monthly_installment)\\n * EMI = [P x R x (1+R)^N]/[(1+R)^N-1]\\n * @param principal The starting amount that is owed on the loan.\\n * @param loanDuration The length of the loan.\\n * @param cycleDuration The length of the loan's payment cycle.\\n * @param apr The annual percentage rate of the loan.\\n */\\n function pmt(\\n uint256 principal,\\n uint32 loanDuration,\\n uint32 cycleDuration,\\n uint16 apr,\\n uint256 daysInYear\\n ) internal pure returns (uint256) {\\n require(\\n loanDuration >= cycleDuration,\\n \\\"PMT: cycle duration < loan duration\\\"\\n );\\n if (apr == 0)\\n return\\n Math.mulDiv(\\n principal,\\n cycleDuration,\\n loanDuration,\\n Math.Rounding.Up\\n );\\n\\n // Number of payment cycles for the duration of the loan\\n uint256 n = Math.ceilDiv(loanDuration, cycleDuration);\\n\\n uint256 one = WadRayMath.wad();\\n uint256 r = WadRayMath.pctToWad(apr).wadMul(cycleDuration).wadDiv(\\n daysInYear\\n );\\n uint256 exp = (one + r).wadPow(n);\\n uint256 numerator = principal.wadMul(r).wadMul(exp);\\n uint256 denominator = exp - one;\\n\\n return numerator.wadDiv(denominator);\\n }\\n}\\n\",\"keccak256\":\"0x78009ffb3737ab7615a1e38a26635d6c06b65b7b7959af46d6ef840d220e70cf\",\"license\":\"MIT\"},\"contracts/libraries/V2Calculations.sol\":{\"content\":\"pragma solidity >=0.8.0 <0.9.0;\\n\\n// SPDX-License-Identifier: MIT\\n\\n// Libraries\\nimport \\\"./NumbersLib.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/Math.sol\\\";\\nimport { Bid } from \\\"../TellerV2Storage.sol\\\";\\nimport { BokkyPooBahsDateTimeLibrary as BPBDTL } from \\\"./DateTimeLib.sol\\\";\\n\\nenum PaymentType {\\n EMI,\\n Bullet\\n}\\n\\nenum PaymentCycleType {\\n Seconds,\\n Monthly\\n}\\n\\nlibrary V2Calculations {\\n using NumbersLib for uint256;\\n\\n /**\\n * @notice Returns the timestamp of the last payment made for a loan.\\n * @param _bid The loan bid struct to get the timestamp for.\\n */\\n function lastRepaidTimestamp(Bid storage _bid)\\n internal\\n view\\n returns (uint32)\\n {\\n return\\n _bid.loanDetails.lastRepaidTimestamp == 0\\n ? _bid.loanDetails.acceptedTimestamp\\n : _bid.loanDetails.lastRepaidTimestamp;\\n }\\n\\n /**\\n * @notice Calculates the amount owed for a loan.\\n * @param _bid The loan bid struct to get the owed amount for.\\n * @param _timestamp The timestamp at which to get the owed amount at.\\n * @param _paymentCycleType The payment cycle type of the loan (Seconds or Monthly).\\n */\\n function calculateAmountOwed(\\n Bid storage _bid,\\n uint256 _timestamp,\\n PaymentCycleType _paymentCycleType,\\n uint32 _paymentCycleDuration\\n )\\n internal\\n view\\n returns (\\n uint256 owedPrincipal_,\\n uint256 duePrincipal_,\\n uint256 interest_\\n )\\n {\\n // Total principal left to pay\\n return\\n calculateAmountOwed(\\n _bid,\\n lastRepaidTimestamp(_bid),\\n _timestamp,\\n _paymentCycleType,\\n _paymentCycleDuration\\n );\\n }\\n\\n function calculateAmountOwed(\\n Bid storage _bid,\\n uint256 _lastRepaidTimestamp,\\n uint256 _timestamp,\\n PaymentCycleType _paymentCycleType,\\n uint32 _paymentCycleDuration\\n )\\n internal\\n view\\n returns (\\n uint256 owedPrincipal_,\\n uint256 duePrincipal_,\\n uint256 interest_\\n )\\n {\\n owedPrincipal_ =\\n _bid.loanDetails.principal -\\n _bid.loanDetails.totalRepaid.principal;\\n\\n uint256 daysInYear = _paymentCycleType == PaymentCycleType.Monthly\\n ? 360 days\\n : 365 days;\\n\\n uint256 interestOwedInAYear = owedPrincipal_.percent(_bid.terms.APR);\\n uint256 owedTime = _timestamp - uint256(_lastRepaidTimestamp);\\n interest_ = (interestOwedInAYear * owedTime) / daysInYear;\\n\\n bool isLastPaymentCycle;\\n {\\n uint256 lastPaymentCycleDuration = _bid.loanDetails.loanDuration %\\n _paymentCycleDuration;\\n if (lastPaymentCycleDuration == 0) {\\n lastPaymentCycleDuration = _paymentCycleDuration;\\n }\\n\\n uint256 endDate = uint256(_bid.loanDetails.acceptedTimestamp) +\\n uint256(_bid.loanDetails.loanDuration);\\n uint256 lastPaymentCycleStart = endDate -\\n uint256(lastPaymentCycleDuration);\\n\\n isLastPaymentCycle =\\n uint256(_timestamp) > lastPaymentCycleStart ||\\n owedPrincipal_ + interest_ <= _bid.terms.paymentCycleAmount;\\n }\\n\\n if (_bid.paymentType == PaymentType.Bullet) {\\n if (isLastPaymentCycle) {\\n duePrincipal_ = owedPrincipal_;\\n }\\n } else {\\n // Default to PaymentType.EMI\\n // Max payable amount in a cycle\\n // NOTE: the last cycle could have less than the calculated payment amount\\n\\n uint256 owedAmount = isLastPaymentCycle\\n ? owedPrincipal_ + interest_\\n : (_bid.terms.paymentCycleAmount * owedTime) /\\n _paymentCycleDuration;\\n\\n duePrincipal_ = Math.min(owedAmount - interest_, owedPrincipal_);\\n }\\n }\\n\\n /**\\n * @notice Calculates the amount owed for a loan for the next payment cycle.\\n * @param _type The payment type of the loan.\\n * @param _cycleType The cycle type set for the loan. (Seconds or Monthly)\\n * @param _principal The starting amount that is owed on the loan.\\n * @param _duration The length of the loan.\\n * @param _paymentCycle The length of the loan's payment cycle.\\n * @param _apr The annual percentage rate of the loan.\\n */\\n function calculatePaymentCycleAmount(\\n PaymentType _type,\\n PaymentCycleType _cycleType,\\n uint256 _principal,\\n uint32 _duration,\\n uint32 _paymentCycle,\\n uint16 _apr\\n ) internal returns (uint256) {\\n uint256 daysInYear = _cycleType == PaymentCycleType.Monthly\\n ? 360 days\\n : 365 days;\\n if (_type == PaymentType.Bullet) {\\n return\\n _principal.percent(_apr).percent(\\n uint256(_paymentCycle).ratioOf(daysInYear, 10),\\n 10\\n );\\n }\\n // Default to PaymentType.EMI\\n return\\n NumbersLib.pmt(\\n _principal,\\n _duration,\\n _paymentCycle,\\n _apr,\\n daysInYear\\n );\\n }\\n\\n function calculateNextDueDate(\\n uint32 _acceptedTimestamp,\\n uint32 _paymentCycle,\\n uint32 _loanDuration,\\n uint32 _lastRepaidTimestamp,\\n PaymentCycleType _bidPaymentCycleType\\n ) public view returns (uint32 dueDate_) {\\n // Calculate due date if payment cycle is set to monthly\\n if (_bidPaymentCycleType == PaymentCycleType.Monthly) {\\n // Calculate the cycle number the last repayment was made\\n uint256 lastPaymentCycle = BPBDTL.diffMonths(\\n _acceptedTimestamp,\\n _lastRepaidTimestamp\\n );\\n if (\\n BPBDTL.getDay(_lastRepaidTimestamp) >\\n BPBDTL.getDay(_acceptedTimestamp)\\n ) {\\n lastPaymentCycle += 2;\\n } else {\\n lastPaymentCycle += 1;\\n }\\n\\n dueDate_ = uint32(\\n BPBDTL.addMonths(_acceptedTimestamp, lastPaymentCycle)\\n );\\n } else if (_bidPaymentCycleType == PaymentCycleType.Seconds) {\\n // Start with the original due date being 1 payment cycle since bid was accepted\\n dueDate_ = _acceptedTimestamp + _paymentCycle;\\n // Calculate the cycle number the last repayment was made\\n uint32 delta = _lastRepaidTimestamp - _acceptedTimestamp;\\n if (delta > 0) {\\n uint32 repaymentCycle = uint32(\\n Math.ceilDiv(delta, _paymentCycle)\\n );\\n dueDate_ += (repaymentCycle * _paymentCycle);\\n }\\n }\\n\\n uint32 endOfLoan = _acceptedTimestamp + _loanDuration;\\n //if we are in the last payment cycle, the next due date is the end of loan duration\\n if (dueDate_ > endOfLoan) {\\n dueDate_ = endOfLoan;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x184335b617baee6e84bf0c90f19526e170594bae9cb2f25385a3d41c1cc435f1\",\"license\":\"MIT\"},\"contracts/libraries/WadRayMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/math/SafeCast.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/math/SafeMath.sol\\\";\\n\\n/**\\n * @title WadRayMath library\\n * @author Multiplier Finance\\n * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)\\n */\\nlibrary WadRayMath {\\n using SafeMath for uint256;\\n\\n uint256 internal constant WAD = 1e18;\\n uint256 internal constant halfWAD = WAD / 2;\\n\\n uint256 internal constant RAY = 1e27;\\n uint256 internal constant halfRAY = RAY / 2;\\n\\n uint256 internal constant WAD_RAY_RATIO = 1e9;\\n uint256 internal constant PCT_WAD_RATIO = 1e14;\\n uint256 internal constant PCT_RAY_RATIO = 1e23;\\n\\n function ray() internal pure returns (uint256) {\\n return RAY;\\n }\\n\\n function wad() internal pure returns (uint256) {\\n return WAD;\\n }\\n\\n function halfRay() internal pure returns (uint256) {\\n return halfRAY;\\n }\\n\\n function halfWad() internal pure returns (uint256) {\\n return halfWAD;\\n }\\n\\n function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return halfWAD.add(a.mul(b)).div(WAD);\\n }\\n\\n function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 halfB = b / 2;\\n\\n return halfB.add(a.mul(WAD)).div(b);\\n }\\n\\n function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {\\n return halfRAY.add(a.mul(b)).div(RAY);\\n }\\n\\n function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 halfB = b / 2;\\n\\n return halfB.add(a.mul(RAY)).div(b);\\n }\\n\\n function rayToWad(uint256 a) internal pure returns (uint256) {\\n uint256 halfRatio = WAD_RAY_RATIO / 2;\\n\\n return halfRatio.add(a).div(WAD_RAY_RATIO);\\n }\\n\\n function rayToPct(uint256 a) internal pure returns (uint16) {\\n uint256 halfRatio = PCT_RAY_RATIO / 2;\\n\\n uint256 val = halfRatio.add(a).div(PCT_RAY_RATIO);\\n return SafeCast.toUint16(val);\\n }\\n\\n function wadToPct(uint256 a) internal pure returns (uint16) {\\n uint256 halfRatio = PCT_WAD_RATIO / 2;\\n\\n uint256 val = halfRatio.add(a).div(PCT_WAD_RATIO);\\n return SafeCast.toUint16(val);\\n }\\n\\n function wadToRay(uint256 a) internal pure returns (uint256) {\\n return a.mul(WAD_RAY_RATIO);\\n }\\n\\n function pctToRay(uint16 a) internal pure returns (uint256) {\\n return uint256(a).mul(RAY).div(1e4);\\n }\\n\\n function pctToWad(uint16 a) internal pure returns (uint256) {\\n return uint256(a).mul(WAD).div(1e4);\\n }\\n\\n /**\\n * @dev calculates base^duration. The code uses the ModExp precompile\\n * @return z base^duration, in ray\\n */\\n function rayPow(uint256 x, uint256 n) internal pure returns (uint256) {\\n return _pow(x, n, RAY, rayMul);\\n }\\n\\n function wadPow(uint256 x, uint256 n) internal pure returns (uint256) {\\n return _pow(x, n, WAD, wadMul);\\n }\\n\\n function _pow(\\n uint256 x,\\n uint256 n,\\n uint256 p,\\n function(uint256, uint256) internal pure returns (uint256) mul\\n ) internal pure returns (uint256 z) {\\n z = n % 2 != 0 ? x : p;\\n\\n for (n /= 2; n != 0; n /= 2) {\\n x = mul(x, x);\\n\\n if (n % 2 != 0) {\\n z = mul(z, x);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2781319be7a96f56966c601c061849fa94dbf9af5ad80a20c40b879a8d03f14a\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6109dc61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80630dcf16581461003a575b600080fd5b61004d6100483660046106d5565b610066565b60405163ffffffff909116815260200160405180910390f35b6000600182600181111561007c5761007c610742565b14156100f857600061009a8763ffffffff168563ffffffff1661019c565b90506100ab8763ffffffff16610223565b6100ba8563ffffffff16610223565b11156100d2576100cb60028261076e565b90506100e0565b6100dd60018261076e565b90505b6100f08763ffffffff168261023d565b91505061016c565b600082600181111561010c5761010c610742565b141561016c5761011c8587610786565b9050600061012a87856107ae565b905063ffffffff81161561016a5760006101508263ffffffff168863ffffffff1661030f565b905061015c87826107d3565b6101669084610786565b9250505b505b60006101788588610786565b90508063ffffffff168263ffffffff161115610192578091505b5095945050505050565b6000818311156101ab57600080fd5b6000806101c36101be6201518087610815565b610349565b5090925090506000806101dc6101be6201518088610815565b509092509050826101ee85600c610829565b826101fa85600c610829565b610204919061076e565b61020e9190610848565b6102189190610848565b979650505050505050565b60006102356101be6201518084610815565b949350505050565b60008080806102526101be6201518088610815565b91945092509050610263858361076e565b9150600c610272600184610848565b61027c9190610815565b610286908461076e565b9250600c610295600184610848565b61029f919061085f565b6102aa90600161076e565b915060006102b884846104bd565b9050808211156102c6578091505b6102d3620151808861085f565b620151806102e2868686610543565b6102ec9190610829565b6102f6919061076e565b94508685101561030557600080fd5b5050505092915050565b6000821561033d5781610323600185610848565b61032d9190610815565b61033890600161076e565b610340565b60005b90505b92915050565b60008080838162253d8c6103608362010bd9610873565b61036a9190610873565b9050600062023ab161037d8360046108b4565b6103879190610939565b905060046103988262023ab16108b4565b6103a3906003610873565b6103ad9190610939565b6103b79083610967565b9150600062164b096103ca846001610873565b6103d690610fa06108b4565b6103e09190610939565b905060046103f0826105b56108b4565b6103fa9190610939565b6104049084610967565b61040f90601f610873565b9250600061098f6104218560506108b4565b61042b9190610939565b90506000605061043d8361098f6108b4565b6104479190610939565b6104519086610967565b905061045e600b83610939565b945061046b85600c6108b4565b610476836002610873565b6104809190610967565b9150848361048f603187610967565b61049a9060646108b4565b6104a49190610873565b6104ae9190610873565b9a919950975095505050505050565b600081600114806104ce5750816003145b806104d95750816005145b806104e45750816007145b806104ef5750816008145b806104fa575081600a145b80610505575081600c145b156105125750601f610343565b816002146105225750601e610343565b61052b83610680565b61053657601c610539565b601d5b60ff169392505050565b60006107b284101561055457600080fd5b838383600062253d8c60046064600c61056e600e88610967565b6105789190610939565b61058488611324610873565b61058e9190610873565b6105989190610939565b6105a39060036108b4565b6105ad9190610939565b600c806105bb600e88610967565b6105c59190610939565b6105d090600c6108b4565b6105db600288610967565b6105e59190610967565b6105f19061016f6108b4565b6105fb9190610939565b6004600c61060a600e89610967565b6106149190610939565b610620896112c0610873565b61062a9190610873565b610636906105b56108b4565b6106409190610939565b61064c617d4b87610967565b6106569190610873565b6106609190610873565b61066a9190610967565b6106749190610967565b98975050505050505050565b600061068d60048361085f565b1580156106a357506106a060648361085f565b15155b8061034357506106b56101908361085f565b1592915050565b803563ffffffff811681146106d057600080fd5b919050565b600080600080600060a086880312156106ed57600080fd5b6106f6866106bc565b9450610704602087016106bc565b9350610712604087016106bc565b9250610720606087016106bc565b915060808601356002811061073457600080fd5b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561078157610781610758565b500190565b600063ffffffff8083168185168083038211156107a5576107a5610758565b01949350505050565b600063ffffffff838116908316818110156107cb576107cb610758565b039392505050565b600063ffffffff808316818516818304811182151516156107f6576107f6610758565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b600082610824576108246107ff565b500490565b600081600019048311821515161561084357610843610758565b500290565b60008282101561085a5761085a610758565b500390565b60008261086e5761086e6107ff565b500690565b600080821280156001600160ff1b038490038513161561089557610895610758565b600160ff1b83900384128116156108ae576108ae610758565b50500190565b60006001600160ff1b03818413828413808216868404861116156108da576108da610758565b600160ff1b60008712828116878305891216156108f9576108f9610758565b6000871292508782058712848416161561091557610915610758565b8785058712818416161561092b5761092b610758565b505050929093029392505050565b600082610948576109486107ff565b600160ff1b82146000198414161561096257610962610758565b500590565b60008083128015600160ff1b85018412161561098557610985610758565b6001600160ff1b03840183138116156109a0576109a0610758565b5050039056fea264697066735822122085b86990aa1c7b40b80895b7bc5bd891b73f79b56cc04d39032a2a9f8205588c64736f6c63430008090033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80630dcf16581461003a575b600080fd5b61004d6100483660046106d5565b610066565b60405163ffffffff909116815260200160405180910390f35b6000600182600181111561007c5761007c610742565b14156100f857600061009a8763ffffffff168563ffffffff1661019c565b90506100ab8763ffffffff16610223565b6100ba8563ffffffff16610223565b11156100d2576100cb60028261076e565b90506100e0565b6100dd60018261076e565b90505b6100f08763ffffffff168261023d565b91505061016c565b600082600181111561010c5761010c610742565b141561016c5761011c8587610786565b9050600061012a87856107ae565b905063ffffffff81161561016a5760006101508263ffffffff168863ffffffff1661030f565b905061015c87826107d3565b6101669084610786565b9250505b505b60006101788588610786565b90508063ffffffff168263ffffffff161115610192578091505b5095945050505050565b6000818311156101ab57600080fd5b6000806101c36101be6201518087610815565b610349565b5090925090506000806101dc6101be6201518088610815565b509092509050826101ee85600c610829565b826101fa85600c610829565b610204919061076e565b61020e9190610848565b6102189190610848565b979650505050505050565b60006102356101be6201518084610815565b949350505050565b60008080806102526101be6201518088610815565b91945092509050610263858361076e565b9150600c610272600184610848565b61027c9190610815565b610286908461076e565b9250600c610295600184610848565b61029f919061085f565b6102aa90600161076e565b915060006102b884846104bd565b9050808211156102c6578091505b6102d3620151808861085f565b620151806102e2868686610543565b6102ec9190610829565b6102f6919061076e565b94508685101561030557600080fd5b5050505092915050565b6000821561033d5781610323600185610848565b61032d9190610815565b61033890600161076e565b610340565b60005b90505b92915050565b60008080838162253d8c6103608362010bd9610873565b61036a9190610873565b9050600062023ab161037d8360046108b4565b6103879190610939565b905060046103988262023ab16108b4565b6103a3906003610873565b6103ad9190610939565b6103b79083610967565b9150600062164b096103ca846001610873565b6103d690610fa06108b4565b6103e09190610939565b905060046103f0826105b56108b4565b6103fa9190610939565b6104049084610967565b61040f90601f610873565b9250600061098f6104218560506108b4565b61042b9190610939565b90506000605061043d8361098f6108b4565b6104479190610939565b6104519086610967565b905061045e600b83610939565b945061046b85600c6108b4565b610476836002610873565b6104809190610967565b9150848361048f603187610967565b61049a9060646108b4565b6104a49190610873565b6104ae9190610873565b9a919950975095505050505050565b600081600114806104ce5750816003145b806104d95750816005145b806104e45750816007145b806104ef5750816008145b806104fa575081600a145b80610505575081600c145b156105125750601f610343565b816002146105225750601e610343565b61052b83610680565b61053657601c610539565b601d5b60ff169392505050565b60006107b284101561055457600080fd5b838383600062253d8c60046064600c61056e600e88610967565b6105789190610939565b61058488611324610873565b61058e9190610873565b6105989190610939565b6105a39060036108b4565b6105ad9190610939565b600c806105bb600e88610967565b6105c59190610939565b6105d090600c6108b4565b6105db600288610967565b6105e59190610967565b6105f19061016f6108b4565b6105fb9190610939565b6004600c61060a600e89610967565b6106149190610939565b610620896112c0610873565b61062a9190610873565b610636906105b56108b4565b6106409190610939565b61064c617d4b87610967565b6106569190610873565b6106609190610873565b61066a9190610967565b6106749190610967565b98975050505050505050565b600061068d60048361085f565b1580156106a357506106a060648361085f565b15155b8061034357506106b56101908361085f565b1592915050565b803563ffffffff811681146106d057600080fd5b919050565b600080600080600060a086880312156106ed57600080fd5b6106f6866106bc565b9450610704602087016106bc565b9350610712604087016106bc565b9250610720606087016106bc565b915060808601356002811061073457600080fd5b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561078157610781610758565b500190565b600063ffffffff8083168185168083038211156107a5576107a5610758565b01949350505050565b600063ffffffff838116908316818110156107cb576107cb610758565b039392505050565b600063ffffffff808316818516818304811182151516156107f6576107f6610758565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b600082610824576108246107ff565b500490565b600081600019048311821515161561084357610843610758565b500290565b60008282101561085a5761085a610758565b500390565b60008261086e5761086e6107ff565b500690565b600080821280156001600160ff1b038490038513161561089557610895610758565b600160ff1b83900384128116156108ae576108ae610758565b50500190565b60006001600160ff1b03818413828413808216868404861116156108da576108da610758565b600160ff1b60008712828116878305891216156108f9576108f9610758565b6000871292508782058712848416161561091557610915610758565b8785058712818416161561092b5761092b610758565b505050929093029392505050565b600082610948576109486107ff565b600160ff1b82146000198414161561096257610962610758565b500590565b60008083128015600160ff1b85018412161561098557610985610758565b6001600160ff1b03840183138116156109a0576109a0610758565b5050039056fea264697066735822122085b86990aa1c7b40b80895b7bc5bd891b73f79b56cc04d39032a2a9f8205588c64736f6c63430008090033", "devdoc": { "kind": "dev", "methods": {}, diff --git a/packages/contracts/deployments/goerli/solcInputs/a6b30c70f10157e1bb4295b984117fe9.json b/packages/contracts/deployments/goerli/solcInputs/a6b30c70f10157e1bb4295b984117fe9.json new file mode 100644 index 000000000..10a5c8fe0 --- /dev/null +++ b/packages/contracts/deployments/goerli/solcInputs/a6b30c70f10157e1bb4295b984117fe9.json @@ -0,0 +1,374 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/metatx/ERC2771ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)\n\npragma solidity ^0.8.9;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Context variant with ERC2771 support.\n */\nabstract contract ERC2771ContextUpgradeable is Initializable, ContextUpgradeable {\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address private immutable _trustedForwarder;\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address trustedForwarder) {\n _trustedForwarder = trustedForwarder;\n }\n\n function isTrustedForwarder(address forwarder) public view virtual returns (bool) {\n return forwarder == _trustedForwarder;\n }\n\n function _msgSender() internal view virtual override returns (address sender) {\n if (isTrustedForwarder(msg.sender)) {\n // The assembly code is more direct than the Solidity version using `abi.decode`.\n /// @solidity memory-safe-assembly\n assembly {\n sender := shr(96, calldataload(sub(calldatasize(), 20)))\n }\n } else {\n return super._msgSender();\n }\n }\n\n function _msgData() internal view virtual override returns (bytes calldata) {\n if (isTrustedForwarder(msg.sender)) {\n return msg.data[:msg.data.length - 20];\n } else {\n return super._msgData();\n }\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n function __Pausable_init() internal onlyInitializing {\n __Pausable_init_unchained();\n }\n\n function __Pausable_init_unchained() internal onlyInitializing {\n _paused = false;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n require(!paused(), \"Pausable: paused\");\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n require(paused(), \"Pausable: not paused\");\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev _Available since v3.1._\n */\ninterface IERC1155ReceiverUpgradeable is IERC165Upgradeable {\n /**\n * @dev Handles the receipt of a single ERC1155 token type. This function is\n * called at the end of a `safeTransferFrom` after the balance has been updated.\n *\n * NOTE: To accept the transfer, this must return\n * `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n * (i.e. 0xf23a6e61, or its own function selector).\n *\n * @param operator The address which initiated the transfer (i.e. msg.sender)\n * @param from The address which previously owned the token\n * @param id The ID of the token being transferred\n * @param value The amount of tokens being transferred\n * @param data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` if transfer is allowed\n */\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 value,\n bytes calldata data\n ) external returns (bytes4);\n\n /**\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\n * is called at the end of a `safeBatchTransferFrom` after the balances have\n * been updated.\n *\n * NOTE: To accept the transfer(s), this must return\n * `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n * (i.e. 0xbc197c81, or its own function selector).\n *\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\n * @param from The address which previously owned the token\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\n * @param data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` if transfer is allowed\n */\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n *\n * _Available since v3.1._\n */\ninterface IERC1155Upgradeable is IERC165Upgradeable {\n /**\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\n */\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n /**\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n * transfers.\n */\n event TransferBatch(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256[] ids,\n uint256[] values\n );\n\n /**\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n * `approved`.\n */\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n /**\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n *\n * If an {URI} event was emitted for `id`, the standard\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n * returned by {IERC1155MetadataURI-uri}.\n */\n event URI(string value, uint256 indexed id);\n\n /**\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function balanceOf(address account, uint256 id) external view returns (uint256);\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n *\n * Requirements:\n *\n * - `accounts` and `ids` must have the same length.\n */\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\n external\n view\n returns (uint256[] memory);\n\n /**\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n *\n * Emits an {ApprovalForAll} event.\n *\n * Requirements:\n *\n * - `operator` cannot be the caller.\n */\n function setApprovalForAll(address operator, bool approved) external;\n\n /**\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n *\n * See {setApprovalForAll}.\n */\n function isApprovedForAll(address account, address operator) external view returns (bool);\n\n /**\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\n *\n * Emits a {TransferSingle} event.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n * acceptance magic value.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n *\n * Emits a {TransferBatch} event.\n *\n * Requirements:\n *\n * - `ids` and `amounts` must have the same length.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n * acceptance magic value.\n */\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) external;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ERC1155ReceiverUpgradeable.sol\";\nimport \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens.\n *\n * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be\n * stuck.\n *\n * @dev _Available since v3.1._\n */\ncontract ERC1155HolderUpgradeable is Initializable, ERC1155ReceiverUpgradeable {\n function __ERC1155Holder_init() internal onlyInitializing {\n }\n\n function __ERC1155Holder_init_unchained() internal onlyInitializing {\n }\n function onERC1155Received(\n address,\n address,\n uint256,\n uint256,\n bytes memory\n ) public virtual override returns (bytes4) {\n return this.onERC1155Received.selector;\n }\n\n function onERC1155BatchReceived(\n address,\n address,\n uint256[] memory,\n uint256[] memory,\n bytes memory\n ) public virtual override returns (bytes4) {\n return this.onERC1155BatchReceived.selector;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155ReceiverUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC1155ReceiverUpgradeable.sol\";\nimport \"../../../utils/introspection/ERC165Upgradeable.sol\";\nimport \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev _Available since v3.1._\n */\nabstract contract ERC1155ReceiverUpgradeable is Initializable, ERC165Upgradeable, IERC1155ReceiverUpgradeable {\n function __ERC1155Receiver_init() internal onlyInitializing {\n }\n\n function __ERC1155Receiver_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {\n return interfaceId == type(IERC1155ReceiverUpgradeable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721Upgradeable.sol\";\nimport \"./IERC721ReceiverUpgradeable.sol\";\nimport \"./extensions/IERC721MetadataUpgradeable.sol\";\nimport \"../../utils/AddressUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport \"../../utils/StringsUpgradeable.sol\";\nimport \"../../utils/introspection/ERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {\n using AddressUpgradeable for address;\n using StringsUpgradeable for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __ERC721_init_unchained(name_, symbol_);\n }\n\n function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {\n return\n interfaceId == type(IERC721Upgradeable).interfaceId ||\n interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: address zero is not a valid owner\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _ownerOf(tokenId);\n require(owner != address(0), \"ERC721: invalid token ID\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n _requireMinted(tokenId);\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overridden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not token owner or approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n _requireMinted(tokenId);\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner or approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner or approved\");\n _safeTransfer(from, to, tokenId, data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist\n */\n function _ownerOf(uint256 tokenId) internal view virtual returns (address) {\n return _owners[tokenId];\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _ownerOf(tokenId) != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId, 1);\n\n // Check that tokenId was not minted by `_beforeTokenTransfer` hook\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n unchecked {\n // Will not overflow unless all 2**256 token ids are minted to the same owner.\n // Given that tokens are minted one by one, it is impossible in practice that\n // this ever happens. Might change if we allow batch minting.\n // The ERC fails to describe this case.\n _balances[to] += 1;\n }\n\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId, 1);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n * This is an internal function that does not check if the sender is authorized to operate on the token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId, 1);\n\n // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook\n owner = ERC721Upgradeable.ownerOf(tokenId);\n\n // Clear approvals\n delete _tokenApprovals[tokenId];\n\n unchecked {\n // Cannot overflow, as that would require more tokens to be burned/transferred\n // out than the owner initially received through minting and transferring in.\n _balances[owner] -= 1;\n }\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId, 1);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721Upgradeable.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId, 1);\n\n // Check that tokenId was not transferred by `_beforeTokenTransfer` hook\n require(ERC721Upgradeable.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n\n // Clear approvals from the previous owner\n delete _tokenApprovals[tokenId];\n\n unchecked {\n // `_balances[from]` cannot overflow for the same reason as described in `_burn`:\n // `from`'s balance is the number of token held, which is at least one before the current\n // transfer.\n // `_balances[to]` could overflow in the conditions described in `_mint`. That would require\n // all 2**256 token ids to be minted, which in practice is impossible.\n _balances[from] -= 1;\n _balances[to] += 1;\n }\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId, 1);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits an {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits an {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Reverts if the `tokenId` has not been minted yet.\n */\n function _requireMinted(uint256 tokenId) internal view virtual {\n require(_exists(tokenId), \"ERC721: invalid token ID\");\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n /// @solidity memory-safe-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is\n * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.\n * - When `from` is zero, the tokens will be minted for `to`.\n * - When `to` is zero, ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n * - `batchSize` is non-zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256, /* firstTokenId */\n uint256 batchSize\n ) internal virtual {\n if (batchSize > 1) {\n if (from != address(0)) {\n _balances[from] -= batchSize;\n }\n if (to != address(0)) {\n _balances[to] += batchSize;\n }\n }\n }\n\n /**\n * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is\n * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.\n * - When `from` is zero, the tokens were minted for `to`.\n * - When `to` is zero, ``from``'s tokens were burned.\n * - `from` and `to` are never both zero.\n * - `batchSize` is non-zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 firstTokenId,\n uint256 batchSize\n ) internal virtual {}\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[44] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721Upgradeable.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721MetadataUpgradeable is IERC721Upgradeable {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721ReceiverUpgradeable {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721Upgradeable is IERC165Upgradeable {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721ReceiverUpgradeable.sol\";\nimport \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC721Receiver} interface.\n *\n * Accepts all token transfers.\n * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.\n */\ncontract ERC721HolderUpgradeable is Initializable, IERC721ReceiverUpgradeable {\n function __ERC721Holder_init() internal onlyInitializing {\n }\n\n function __ERC721Holder_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev See {IERC721Receiver-onERC721Received}.\n *\n * Always returns `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address,\n address,\n uint256,\n bytes memory\n ) public virtual override returns (bytes4) {\n return this.onERC721Received.selector;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev These functions deal with verification of Merkle Tree proofs.\n *\n * The tree and the proofs can be generated using our\n * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].\n * You will find a quickstart guide in the readme.\n *\n * WARNING: You should avoid using leaf values that are 64 bytes long prior to\n * hashing, or use a hash function other than keccak256 for hashing leaves.\n * This is because the concatenation of a sorted pair of internal nodes in\n * the merkle tree could be reinterpreted as a leaf value.\n * OpenZeppelin's JavaScript library generates merkle trees that are safe\n * against this attack out of the box.\n */\nlibrary MerkleProofUpgradeable {\n /**\n * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n * defined by `root`. For this, a `proof` must be provided, containing\n * sibling hashes on the branch from the leaf to the root of the tree. Each\n * pair of leaves and each pair of pre-images are assumed to be sorted.\n */\n function verify(\n bytes32[] memory proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProof(proof, leaf) == root;\n }\n\n /**\n * @dev Calldata version of {verify}\n *\n * _Available since v4.7._\n */\n function verifyCalldata(\n bytes32[] calldata proof,\n bytes32 root,\n bytes32 leaf\n ) internal pure returns (bool) {\n return processProofCalldata(proof, leaf) == root;\n }\n\n /**\n * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up\n * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt\n * hash matches the root of the tree. When processing the proof, the pairs\n * of leafs & pre-images are assumed to be sorted.\n *\n * _Available since v4.4._\n */\n function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Calldata version of {processProof}\n *\n * _Available since v4.7._\n */\n function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {\n bytes32 computedHash = leaf;\n for (uint256 i = 0; i < proof.length; i++) {\n computedHash = _hashPair(computedHash, proof[i]);\n }\n return computedHash;\n }\n\n /**\n * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by\n * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.\n *\n * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * _Available since v4.7._\n */\n function multiProofVerify(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProof(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Calldata version of {multiProofVerify}\n *\n * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * _Available since v4.7._\n */\n function multiProofVerifyCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32 root,\n bytes32[] memory leaves\n ) internal pure returns (bool) {\n return processMultiProofCalldata(proof, proofFlags, leaves) == root;\n }\n\n /**\n * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction\n * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another\n * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false\n * respectively.\n *\n * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree\n * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the\n * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).\n *\n * _Available since v4.7._\n */\n function processMultiProof(\n bytes32[] memory proof,\n bool[] memory proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n /**\n * @dev Calldata version of {processMultiProof}.\n *\n * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.\n *\n * _Available since v4.7._\n */\n function processMultiProofCalldata(\n bytes32[] calldata proof,\n bool[] calldata proofFlags,\n bytes32[] memory leaves\n ) internal pure returns (bytes32 merkleRoot) {\n // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by\n // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the\n // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of\n // the merkle tree.\n uint256 leavesLen = leaves.length;\n uint256 totalHashes = proofFlags.length;\n\n // Check proof validity.\n require(leavesLen + proof.length - 1 == totalHashes, \"MerkleProof: invalid multiproof\");\n\n // The xxxPos values are \"pointers\" to the next value to consume in each array. All accesses are done using\n // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's \"pop\".\n bytes32[] memory hashes = new bytes32[](totalHashes);\n uint256 leafPos = 0;\n uint256 hashPos = 0;\n uint256 proofPos = 0;\n // At each step, we compute the next hash using two values:\n // - a value from the \"main queue\". If not all leaves have been consumed, we get the next leaf, otherwise we\n // get the next hash.\n // - depending on the flag, either another value for the \"main queue\" (merging branches) or an element from the\n // `proof` array.\n for (uint256 i = 0; i < totalHashes; i++) {\n bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];\n bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];\n hashes[i] = _hashPair(a, b);\n }\n\n if (totalHashes > 0) {\n return hashes[totalHashes - 1];\n } else if (leavesLen > 0) {\n return leaves[0];\n } else {\n return proof[0];\n }\n }\n\n function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {\n return a < b ? _efficientHash(a, b) : _efficientHash(b, a);\n }\n\n function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, a)\n mstore(0x20, b)\n value := keccak256(0x00, 0x40)\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {\n function __ERC165_init() internal onlyInitializing {\n }\n\n function __ERC165_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUpgradeable {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/MathUpgradeable.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary StringsUpgradeable {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = MathUpgradeable.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, MathUpgradeable.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSetUpgradeable {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the proxy with `beacon`.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\n * constructor.\n *\n * Requirements:\n *\n * - `beacon` must be a contract with the interface {IBeacon}.\n */\n constructor(address beacon, bytes memory data) payable {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n\n /**\n * @dev Returns the current beacon address.\n */\n function _beacon() internal view virtual returns (address) {\n return _getBeacon();\n }\n\n /**\n * @dev Returns the current implementation address of the associated beacon.\n */\n function _implementation() internal view virtual override returns (address) {\n return IBeacon(_getBeacon()).implementation();\n }\n\n /**\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n *\n * Requirements:\n *\n * - `beacon` must be a contract.\n * - The implementation returned by `beacon` must be a contract.\n */\n function _setBeacon(address beacon, bytes memory data) internal virtual {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n *\n * @custom:oz-upgrades-unsafe-allow delegatecall\n */\nabstract contract ERC1967Upgrade {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Emitted when the beacon is upgraded.\n */\n event BeaconUpgraded(address indexed beacon);\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(\n address newBeacon,\n bytes memory data,\n bool forceCall\n ) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC1155/IERC1155.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n *\n * _Available since v3.1._\n */\ninterface IERC1155 is IERC165 {\n /**\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\n */\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n /**\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n * transfers.\n */\n event TransferBatch(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256[] ids,\n uint256[] values\n );\n\n /**\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n * `approved`.\n */\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n /**\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n *\n * If an {URI} event was emitted for `id`, the standard\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n * returned by {IERC1155MetadataURI-uri}.\n */\n event URI(string value, uint256 indexed id);\n\n /**\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function balanceOf(address account, uint256 id) external view returns (uint256);\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n *\n * Requirements:\n *\n * - `accounts` and `ids` must have the same length.\n */\n function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\n external\n view\n returns (uint256[] memory);\n\n /**\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n *\n * Emits an {ApprovalForAll} event.\n *\n * Requirements:\n *\n * - `operator` cannot be the caller.\n */\n function setApprovalForAll(address operator, bool approved) external;\n\n /**\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n *\n * See {setApprovalForAll}.\n */\n function isApprovedForAll(address account, address operator) external view returns (bool);\n\n /**\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\n *\n * Emits a {TransferSingle} event.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n * acceptance magic value.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n *\n * Emits a {TransferBatch} event.\n *\n * Requirements:\n *\n * - `ids` and `amounts` must have the same length.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n * acceptance magic value.\n */\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) external;\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.2._\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v2.5._\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.2._\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v2.5._\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v2.5._\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v2.5._\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v2.5._\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n *\n * _Available since v3.0._\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.7._\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.7._\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n *\n * _Available since v3.0._\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n uint256 c = a + b;\n if (c < a) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b > a) return (false, 0);\n return (true, a - b);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n *\n * _Available since v3.4._\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) return (true, 0);\n uint256 c = a * b;\n if (c / a != b) return (false, 0);\n return (true, c);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a / b);\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n *\n * _Available since v3.4._\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n unchecked {\n if (b == 0) return (false, 0);\n return (true, a % b);\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator.\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return a % b;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {trySub}.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b <= a, errorMessage);\n return a - b;\n }\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a / b;\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * reverting with custom message when dividing by zero.\n *\n * CAUTION: This function is deprecated because it requires allocating memory for the error\n * message unnecessarily. For custom revert reasons use {tryMod}.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n unchecked {\n require(b > 0, errorMessage);\n return a % b;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/bundle/interfaces/ICollateralBundle.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\n/**\n * Group together arbitrary ERC20, ERC721 and ERC1155 tokens into a single bundle.\n *\n * The `Token` struct is a generic type that can describe any ERC20, ERC721 or ERC1155 token.\n * The `Bundle` struct is a data structure to track a group/bundle of multiple assets i.e. ERC20,\n * ERC721 and ERC1155 tokens, each described as a `Token`.\n *\n * Expressing tokens as the `Token` type, and grouping them as a `Bundle` allows for writing generic\n * logic to handle any ERC20, ERC721 or ERC1155 tokens.\n */\n\n/// @notice The type of assets that can be bundled.\nenum CollateralType {\n ERC20,\n ERC721,\n ERC1155\n}\n\n/**\n * @notice A generic interface to describe any ERC20, ERC721 or ERC1155 token.\n * @param _collateralType The token type (ERC20 / ERC721 / ERC1155) of the asset.\n * @param _amount The amount of the asset, if the asset is an ERC20 / ERC1155 fungible token.\n * @param _tokenId The token Id of the asset, if the asset is an ERC721 / ERC1155 NFT.\n * @param _collateralAddress The contract address of the asset.\n *\n */\nstruct Collateral {\n CollateralType _collateralType;\n uint256 _amount;\n uint256 _tokenId;\n address _collateralAddress;\n}\n\ninterface ICollateralBundle {\n /**\n * @notice An internal data structure to track a group / bundle of multiple assets i.e. `Token`s.\n *\n * @param count The total number of assets i.e. `Collateral` in a bundle.\n * @param collaterals Mapping from a UID -> to a unique asset i.e. `Collateral` in the bundle.\n */\n struct CollateralBundleInfo {\n uint256 count;\n mapping(uint256 => Collateral) collaterals;\n }\n}\n" + }, + "contracts/bundle/lib/CurrencyTransferLib.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\n/// @author thirdweb\n\n// Helper interfaces\nimport { IWETH } from \"../../interfaces/IWETH.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nlibrary CurrencyTransferLib {\n using SafeERC20 for IERC20;\n\n /// @dev The address interpreted as native token of the chain.\n address public constant NATIVE_TOKEN =\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @dev Transfers a given amount of currency.\n function transferCurrency(\n address _currency,\n address _from,\n address _to,\n uint256 _amount\n ) internal {\n if (_amount == 0) {\n return;\n }\n\n if (_currency == NATIVE_TOKEN) {\n safeTransferNativeToken(_to, _amount);\n } else {\n safeTransferERC20(_currency, _from, _to, _amount);\n }\n }\n\n /// @dev Transfers a given amount of currency. (With native token wrapping)\n function transferCurrencyWithWrapper(\n address _currency,\n address _from,\n address _to,\n uint256 _amount,\n address _nativeTokenWrapper\n ) internal {\n if (_amount == 0) {\n return;\n }\n\n if (_currency == NATIVE_TOKEN) {\n if (_from == address(this)) {\n // withdraw from weth then transfer withdrawn native token to recipient\n IWETH(_nativeTokenWrapper).withdraw(_amount);\n safeTransferNativeTokenWithWrapper(\n _to,\n _amount,\n _nativeTokenWrapper\n );\n } else if (_to == address(this)) {\n // store native currency in weth\n require(_amount == msg.value, \"msg.value != amount\");\n IWETH(_nativeTokenWrapper).deposit{ value: _amount }();\n } else {\n safeTransferNativeTokenWithWrapper(\n _to,\n _amount,\n _nativeTokenWrapper\n );\n }\n } else {\n safeTransferERC20(_currency, _from, _to, _amount);\n }\n }\n\n /// @dev Transfer `amount` of ERC20 token from `from` to `to`.\n function safeTransferERC20(\n address _currency,\n address _from,\n address _to,\n uint256 _amount\n ) internal {\n if (_from == _to) {\n return;\n }\n\n if (_from == address(this)) {\n IERC20(_currency).safeTransfer(_to, _amount);\n } else {\n IERC20(_currency).safeTransferFrom(_from, _to, _amount);\n }\n }\n\n /// @dev Transfers `amount` of native token to `to`.\n function safeTransferNativeToken(address to, uint256 value) internal {\n // solhint-disable avoid-low-level-calls\n // slither-disable-next-line low-level-calls\n (bool success, ) = to.call{ value: value }(\"\");\n require(success, \"native token transfer failed\");\n }\n\n /// @dev Transfers `amount` of native token to `to`. (With native token wrapping)\n function safeTransferNativeTokenWithWrapper(\n address to,\n uint256 value,\n address _nativeTokenWrapper\n ) internal {\n // solhint-disable avoid-low-level-calls\n // slither-disable-next-line low-level-calls\n (bool success, ) = to.call{ value: value }(\"\");\n if (!success) {\n IWETH(_nativeTokenWrapper).deposit{ value: value }();\n IERC20(_nativeTokenWrapper).safeTransfer(to, value);\n }\n }\n}\n" + }, + "contracts/bundle/TokenBundle.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\n/// @author thirdweb\n/// https://github.com/thirdweb-dev/contracts/tree/main/contracts/multiwrap\n\nimport \"./interfaces/ICollateralBundle.sol\";\nimport \"./lib/CurrencyTransferLib.sol\";\n\ninterface IERC165 {\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n/**\n * @title Token Bundle\n * @notice `TokenBundle` contract extension allows bundling-up of ERC20/ERC721/ERC1155 and native-tokan assets\n * in a data structure, and provides logic for setting/getting IDs and URIs for created bundles.\n * @dev See {ITokenBundle}\n */\n\nabstract contract TokenBundle is ICollateralBundle {\n /// @dev Mapping from bundle UID => bundle info.\n mapping(uint256 => CollateralBundleInfo) private bundle;\n\n /// @dev The number of bundles that have been created\n uint256 bundleCount;\n\n /// @dev Returns the total number of assets in a particular bundle.\n function getTokenCountOfBundle(uint256 _bundleId)\n public\n view\n returns (uint256)\n {\n return bundle[_bundleId].count;\n }\n\n /// @dev Returns an asset contained in a particular bundle, at a particular index.\n function getTokenOfBundle(uint256 _bundleId, uint256 index)\n public\n view\n returns (Collateral memory)\n {\n return bundle[_bundleId].collaterals[index];\n }\n\n /// @dev Returns the struct of a particular bundle.\n /* function getBundleInfo(uint256 _bundleId) public view returns (CollateralBundleInfo memory) {\n return bundle[_bundleId];\n }*/\n\n /// @dev Lets the calling contract create a bundle, by passing in a list of tokens and a unique id.\n function _createBundle(Collateral[] memory _tokensToBind)\n internal\n returns (uint256 bundleId_)\n {\n bundleId_ = bundleCount++;\n\n uint256 targetCount = _tokensToBind.length;\n\n require(targetCount > 0, \"!Tokens\");\n require(bundle[bundleId_].count == 0, \"Token bundle id exists\");\n\n for (uint256 i = 0; i < targetCount; i += 1) {\n _checkTokenType(_tokensToBind[i]);\n bundle[bundleId_].collaterals[i] = _tokensToBind[i];\n }\n\n bundle[bundleId_].count = targetCount;\n }\n\n /// @dev Lets the calling contract update a bundle, by passing in a list of tokens and a unique id.\n function _updateBundle(Collateral[] memory _tokensToBind, uint256 _bundleId)\n internal\n {\n require(_tokensToBind.length > 0, \"!Tokens\");\n\n uint256 currentCount = bundle[_bundleId].count;\n uint256 targetCount = _tokensToBind.length;\n uint256 check = currentCount > targetCount ? currentCount : targetCount;\n\n for (uint256 i = 0; i < check; i += 1) {\n if (i < targetCount) {\n _checkTokenType(_tokensToBind[i]);\n bundle[_bundleId].collaterals[i] = _tokensToBind[i];\n } else if (i < currentCount) {\n delete bundle[_bundleId].collaterals[i];\n }\n }\n\n bundle[_bundleId].count = targetCount;\n }\n\n /// @dev Lets the calling contract add a token to a bundle for a unique bundle id and index.\n function _addTokenInBundle(\n Collateral memory _tokenToBind,\n uint256 _bundleId\n ) internal {\n _checkTokenType(_tokenToBind);\n uint256 id = bundle[_bundleId].count;\n\n bundle[_bundleId].collaterals[id] = _tokenToBind;\n bundle[_bundleId].count += 1;\n }\n\n /// @dev Lets the calling contract update a token in a bundle for a unique bundle id and index.\n function _updateTokenInBundle(\n Collateral memory _tokenToBind,\n uint256 _bundleId,\n uint256 _index\n ) internal {\n require(_index < bundle[_bundleId].count, \"index DNE\");\n _checkTokenType(_tokenToBind);\n bundle[_bundleId].collaterals[_index] = _tokenToBind;\n }\n\n /// @dev Checks if the type of asset-contract is same as the TokenType specified.\n function _checkTokenType(Collateral memory _token) internal view {\n if (_token._collateralType == CollateralType.ERC721) {\n try\n IERC165(_token._collateralAddress).supportsInterface(0x80ac58cd)\n returns (bool supported721) {\n require(\n supported721,\n \"TokenBundle: ERC721 Interface Not Supported\"\n );\n } catch {\n revert(\"TokenBundle: ERC721 Interface Not Supported\");\n }\n } else if (_token._collateralType == CollateralType.ERC1155) {\n try\n IERC165(_token._collateralAddress).supportsInterface(0xd9b67a26)\n returns (bool supported1155) {\n require(\n supported1155,\n \"TokenBundle: ERC1155 Interface Not Supported\"\n );\n } catch {\n revert(\"TokenBundle: ERC1155 Interface Not Supported\");\n }\n } else if (_token._collateralType == CollateralType.ERC20) {\n if (_token._collateralAddress != CurrencyTransferLib.NATIVE_TOKEN) {\n // 0x36372b07\n try\n IERC165(_token._collateralAddress).supportsInterface(\n 0x80ac58cd\n )\n returns (bool supported721) {\n require(!supported721, \"!TokenType\");\n\n try\n IERC165(_token._collateralAddress).supportsInterface(\n 0xd9b67a26\n )\n returns (bool supported1155) {\n require(!supported1155, \"!TokenType\");\n } catch Error(string memory) {} catch {}\n } catch Error(string memory) {} catch {}\n }\n }\n }\n\n /// @dev Lets the calling contract set/update the uri of a particular bundle.\n /* function _setUriOfBundle(string memory _uri, uint256 _bundleId) internal {\n bundle[_bundleId].uri = _uri;\n }*/\n\n /// @dev Lets the calling contract delete a particular bundle.\n function _deleteBundle(uint256 _bundleId) internal {\n for (uint256 i = 0; i < bundle[_bundleId].count; i += 1) {\n delete bundle[_bundleId].collaterals[i];\n }\n bundle[_bundleId].count = 0;\n }\n}\n" + }, + "contracts/bundle/TokenStore.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\n/// @author thirdweb\n\n// ========== External imports ==========\n\nimport \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol\";\n\n// ========== Internal imports ==========\n\nimport { Collateral, CollateralType } from \"./interfaces/ICollateralBundle.sol\";\nimport { TokenBundle, ICollateralBundle } from \"./TokenBundle.sol\";\nimport \"./lib/CurrencyTransferLib.sol\";\n\n/**\n * @title Token Store\n * @notice `TokenStore` contract extension allows bundling-up of ERC20/ERC721/ERC1155 and native-tokan assets\n * and provides logic for storing, releasing, and transferring them from the extending contract.\n * @dev See {CurrencyTransferLib}\n */\n\ncontract TokenStore is\n TokenBundle,\n ERC721HolderUpgradeable,\n ERC1155HolderUpgradeable\n{\n /// @dev The address of the native token wrapper contract.\n /*address internal immutable nativeTokenWrapper;\n\n constructor(address _nativeTokenWrapper) {\n nativeTokenWrapper = _nativeTokenWrapper;\n }*/\n\n /// @dev Store / escrow multiple ERC1155, ERC721, ERC20 tokens.\n function _storeTokens(\n address _tokenOwner,\n Collateral[] memory _tokens\n )\n internal\n returns (\n //string memory _uriForTokens\n uint256 bundleId_\n )\n {\n bundleId_ = _createBundle(_tokens);\n //_setUriOfBundle(_uriForTokens, _idForTokens);\n _transferTokenBatch(_tokenOwner, address(this), _tokens);\n }\n\n /// @dev Release stored / escrowed ERC1155, ERC721, ERC20 tokens.\n function _releaseTokens(\n address _recipient,\n uint256 _bundleId\n ) internal virtual returns (uint256, Collateral[] memory) {\n uint256 count = getTokenCountOfBundle(_bundleId);\n Collateral[] memory tokensToRelease = new Collateral[](count);\n\n for (uint256 i = 0; i < count; i += 1) {\n tokensToRelease[i] = getTokenOfBundle(_bundleId, i);\n }\n\n _deleteBundle(_bundleId);\n\n _transferTokenBatch(address(this), _recipient, tokensToRelease);\n\n return (count, tokensToRelease);\n }\n\n /// @dev Transfers an arbitrary ERC20 / ERC721 / ERC1155 token.\n function _transferToken(\n address _from,\n address _to,\n Collateral memory _token\n ) internal {\n if (_token._collateralType == CollateralType.ERC20) {\n CurrencyTransferLib.transferCurrency(\n _token._collateralAddress,\n _from,\n _to,\n _token._amount\n );\n } else if (_token._collateralType == CollateralType.ERC721) {\n IERC721(_token._collateralAddress).safeTransferFrom(\n _from,\n _to,\n _token._tokenId\n );\n } else if (_token._collateralType == CollateralType.ERC1155) {\n IERC1155(_token._collateralAddress).safeTransferFrom(\n _from,\n _to,\n _token._tokenId,\n _token._amount,\n \"\"\n );\n }\n }\n\n /// @dev Transfers multiple arbitrary ERC20 / ERC721 / ERC1155 tokens.\n function _transferTokenBatch(\n address _from,\n address _to,\n Collateral[] memory _tokens\n ) internal {\n //make sure this cannot cause issues\n uint256 nativeTokenValue;\n for (uint256 i = 0; i < _tokens.length; i += 1) {\n if (\n _tokens[i]._collateralAddress ==\n CurrencyTransferLib.NATIVE_TOKEN &&\n _to == address(this)\n ) {\n nativeTokenValue += _tokens[i]._amount;\n } else {\n _transferToken(_from, _to, _tokens[i]);\n }\n }\n if (nativeTokenValue != 0) {\n Collateral memory _nativeToken = Collateral({\n _collateralAddress: CurrencyTransferLib.NATIVE_TOKEN,\n _collateralType: CollateralType.ERC20,\n _tokenId: 0,\n _amount: nativeTokenValue\n });\n _transferToken(_from, _to, _nativeToken);\n }\n }\n}\n" + }, + "contracts/CollateralManagerV1.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n// Libraries\nimport \"@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol\";\n\n// Interfaces\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\";\nimport \"./interfaces/ICollateralManagerV1.sol\";\nimport { ICollateralEscrowV1 } from \"./interfaces/escrow/ICollateralEscrowV1.sol\";\nimport { Collateral, CollateralType } from \"./bundle/interfaces/ICollateralBundle.sol\";\n\nimport \"./interfaces/ITellerV2.sol\";\n\ncontract CollateralManagerV1 is OwnableUpgradeable, ICollateralManagerV1 {\n /* Storage */\n using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n ITellerV2 public tellerV2;\n address private collateralEscrowBeacon; // The address of the escrow contract beacon\n\n // bidIds -> collateralEscrow\n mapping(uint256 => address) public _escrows;\n // bidIds -> validated collateral info\n mapping(uint256 => CollateralInfo) internal _bidCollaterals;\n\n /**\n * Since collateralInfo is mapped (address assetAddress => Collateral) that means\n * that only a single tokenId per nft per loan can be collateralized.\n * Ex. Two bored apes cannot be used as collateral for a single loan.\n */\n struct CollateralInfo {\n EnumerableSetUpgradeable.AddressSet collateralAddresses;\n mapping(address => Collateral) collateralInfo;\n }\n\n /* Events */\n event CollateralEscrowDeployed(uint256 _bidId, address _collateralEscrow);\n event CollateralCommitted(\n uint256 _bidId,\n CollateralType _type,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId\n );\n event CollateralClaimed(uint256 _bidId);\n event CollateralDeposited(\n uint256 _bidId,\n CollateralType _type,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId\n );\n event CollateralWithdrawn(\n uint256 _bidId,\n CollateralType _type,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId,\n address _recipient\n );\n\n /* Modifiers */\n modifier onlyTellerV2() {\n require(_msgSender() == address(tellerV2), \"Sender not authorized\");\n _;\n }\n\n /* External Functions */\n\n /**\n * @notice Initializes the collateral manager.\n * @param _collateralEscrowBeacon The address of the escrow implementation.\n * @param _tellerV2 The address of the protocol.\n */\n function initialize(address _collateralEscrowBeacon, address _tellerV2)\n external\n initializer\n {\n collateralEscrowBeacon = _collateralEscrowBeacon;\n tellerV2 = ITellerV2(_tellerV2);\n __Ownable_init_unchained();\n }\n\n /**\n * @notice Sets the address of the Beacon contract used for the collateral escrow contracts.\n * @param _collateralEscrowBeacon The address of the Beacon contract.\n */\n function setCollateralEscrowBeacon(address _collateralEscrowBeacon)\n external\n reinitializer(2)\n {\n collateralEscrowBeacon = _collateralEscrowBeacon;\n }\n\n /**\n * @notice Checks to see if a bid is backed by collateral.\n * @param _bidId The id of the bid to check.\n */\n\n function isBidCollateralBacked(uint256 _bidId)\n public\n virtual\n returns (bool)\n {\n return _bidCollaterals[_bidId].collateralAddresses.length() > 0;\n }\n\n /**\n * @notice Checks the validity of a borrower's multiple collateral balances and commits it to a bid.\n * @param _bidId The id of the associated bid.\n * @param _collateralInfo Additional information about the collateral assets.\n * @return validation_ Boolean indicating if the collateral balances were validated.\n */\n function commitCollateral(\n uint256 _bidId,\n Collateral[] calldata _collateralInfo\n ) public onlyTellerV2 returns (bool validation_) {\n address borrower = tellerV2.getLoanBorrower(_bidId);\n require(borrower != address(0), \"Loan has no borrower\");\n (validation_, ) = checkBalances(borrower, _collateralInfo);\n\n //if the collateral info is valid, call commitCollateral for each one\n if (validation_) {\n for (uint256 i; i < _collateralInfo.length; i++) {\n Collateral memory info = _collateralInfo[i];\n _commitCollateral(_bidId, info);\n }\n }\n }\n\n //this is not used for anything\n /**\n * @notice Checks the validity of a borrower's collateral balance and commits it to a bid.\n * @param _bidId The id of the associated bid.\n * @param _collateralInfo Additional information about the collateral asset.\n * @return validation_ Boolean indicating if the collateral balance was validated.\n */\n function commitCollateral(\n uint256 _bidId,\n Collateral calldata _collateralInfo\n ) public onlyTellerV2 returns (bool validation_) {\n address borrower = tellerV2.getLoanBorrower(_bidId);\n require(borrower != address(0), \"Loan has no borrower\");\n validation_ = _checkBalance(borrower, _collateralInfo);\n if (validation_) {\n _commitCollateral(_bidId, _collateralInfo);\n }\n }\n\n /**\n * @notice Re-checks the validity of a borrower's collateral balance committed to a bid.\n * @param _bidId The id of the associated bid.\n * @return validation_ Boolean indicating if the collateral balance was validated.\n */\n function revalidateCollateral(uint256 _bidId)\n external\n returns (bool validation_)\n {\n Collateral[] memory collateralInfos = getCollateralInfo(_bidId);\n address borrower = tellerV2.getLoanBorrower(_bidId);\n (validation_, ) = _checkBalances(borrower, collateralInfos, true);\n }\n\n /**\n * @notice Checks the validity of a borrower's multiple collateral balances.\n * @param _borrowerAddress The address of the borrower holding the collateral.\n * @param _collateralInfo Additional information about the collateral assets.\n */\n function checkBalances(\n address _borrowerAddress,\n Collateral[] calldata _collateralInfo\n ) public returns (bool validated_, bool[] memory checks_) {\n return _checkBalances(_borrowerAddress, _collateralInfo, false);\n }\n\n /**\n * @notice Deploys a new collateral escrow and deposits collateral.\n * @param _bidId The associated bidId of the collateral escrow.\n */\n function deployAndDeposit(uint256 _bidId) external onlyTellerV2 {\n if (isBidCollateralBacked(_bidId)) {\n //attempt deploy a new collateral escrow contract if there is not already one. Otherwise fetch it.\n (address proxyAddress, ) = _deployEscrow(_bidId);\n _escrows[_bidId] = proxyAddress;\n\n //for each bid collateral associated with this loan, deposit the collateral into escrow\n for (\n uint256 i;\n i < _bidCollaterals[_bidId].collateralAddresses.length();\n i++\n ) {\n _deposit(\n _bidId,\n _bidCollaterals[_bidId].collateralInfo[\n _bidCollaterals[_bidId].collateralAddresses.at(i)\n ]\n );\n }\n\n emit CollateralEscrowDeployed(_bidId, proxyAddress);\n }\n }\n\n /**\n * @notice Gets the address of a deployed escrow.\n * @notice _bidId The bidId to return the escrow for.\n * @return The address of the escrow.\n */\n function getEscrow(uint256 _bidId) external view returns (address) {\n return _escrows[_bidId];\n }\n\n /**\n * @notice Gets the collateral info for a given bid id.\n * @param _bidId The bidId to return the collateral info for.\n * @return infos_ The stored collateral info.\n */\n function getCollateralInfo(uint256 _bidId)\n public\n view\n returns (Collateral[] memory infos_)\n {\n CollateralInfo storage collateral = _bidCollaterals[_bidId];\n address[] memory collateralAddresses = collateral\n .collateralAddresses\n .values();\n infos_ = new Collateral[](collateralAddresses.length);\n for (uint256 i; i < collateralAddresses.length; i++) {\n infos_[i] = collateral.collateralInfo[collateralAddresses[i]];\n }\n }\n\n /**\n * @notice Gets the collateral asset amount for a given bid id on the TellerV2 contract.\n * @param _bidId The ID of a bid on TellerV2.\n * @param _collateralAddress An address used as collateral.\n * @return amount_ The amount of collateral of type _collateralAddress.\n */\n function getCollateralAmount(uint256 _bidId, address _collateralAddress)\n public\n view\n returns (uint256 amount_)\n {\n amount_ = _bidCollaterals[_bidId]\n .collateralInfo[_collateralAddress]\n ._amount;\n }\n\n /**\n * @notice Withdraws deposited collateral from the created escrow of a bid that has been successfully repaid.\n * @param _bidId The id of the bid to withdraw collateral for.\n */\n function withdraw(uint256 _bidId) external {\n BidState bidState = tellerV2.getBidState(_bidId);\n\n require(bidState == BidState.PAID, \"collateral cannot be withdrawn\");\n\n _withdraw(_bidId, tellerV2.getLoanBorrower(_bidId));\n\n emit CollateralClaimed(_bidId);\n }\n\n /**\n * @notice Withdraws deposited collateral from the created escrow of a bid that has been CLOSED after being defaulted.\n * @param _bidId The id of the bid to withdraw collateral for.\n */\n function lenderClaimCollateral(uint256 _bidId) external onlyTellerV2 {\n if (isBidCollateralBacked(_bidId)) {\n BidState bidState = tellerV2.getBidState(_bidId);\n\n require(\n bidState == BidState.CLOSED,\n \"Loan has not been liquidated\"\n );\n\n _withdraw(_bidId, tellerV2.getLoanLender(_bidId));\n emit CollateralClaimed(_bidId);\n }\n }\n\n /**\n * @notice Sends the deposited collateral to a liquidator of a bid.\n * @notice Can only be called by the protocol.\n * @param _bidId The id of the liquidated bid.\n * @param _liquidatorAddress The address of the liquidator to send the collateral to.\n */\n function liquidateCollateral(uint256 _bidId, address _liquidatorAddress)\n external\n onlyTellerV2\n {\n if (isBidCollateralBacked(_bidId)) {\n BidState bidState = tellerV2.getBidState(_bidId);\n require(\n bidState == BidState.LIQUIDATED,\n \"Loan has not been liquidated\"\n );\n _withdraw(_bidId, _liquidatorAddress);\n }\n }\n\n /* Internal Functions */\n\n /**\n * @notice Deploys a new collateral escrow.\n * @param _bidId The associated bidId of the collateral escrow.\n */\n function _deployEscrow(uint256 _bidId)\n internal\n virtual\n returns (address proxyAddress_, address borrower_)\n {\n proxyAddress_ = _escrows[_bidId];\n // Get bid info\n borrower_ = tellerV2.getLoanBorrower(_bidId);\n if (proxyAddress_ == address(0)) {\n require(borrower_ != address(0), \"Bid does not exist\");\n\n BeaconProxy proxy = new BeaconProxy(\n collateralEscrowBeacon,\n abi.encodeWithSelector(\n ICollateralEscrowV1.initialize.selector,\n _bidId\n )\n );\n proxyAddress_ = address(proxy);\n }\n }\n\n /*\n * @notice Deploys a new collateral escrow contract. Deposits collateral into a collateral escrow.\n * @param _bidId The associated bidId of the collateral escrow.\n * @param collateralInfo The collateral info to deposit.\n\n */\n function _deposit(uint256 _bidId, Collateral memory collateralInfo)\n internal\n virtual\n {\n require(collateralInfo._amount > 0, \"Collateral not validated\");\n (address escrowAddress, address borrower) = _deployEscrow(_bidId);\n ICollateralEscrowV1 collateralEscrow = ICollateralEscrowV1(\n escrowAddress\n );\n // Pull collateral from borrower & deposit into escrow\n if (collateralInfo._collateralType == CollateralType.ERC20) {\n IERC20Upgradeable(collateralInfo._collateralAddress).transferFrom(\n borrower,\n address(this),\n collateralInfo._amount\n );\n IERC20Upgradeable(collateralInfo._collateralAddress).approve(\n escrowAddress,\n collateralInfo._amount\n );\n collateralEscrow.depositAsset(\n CollateralType.ERC20,\n collateralInfo._collateralAddress,\n collateralInfo._amount,\n 0\n );\n } else if (collateralInfo._collateralType == CollateralType.ERC721) {\n IERC721Upgradeable(collateralInfo._collateralAddress).transferFrom(\n borrower,\n address(this),\n collateralInfo._tokenId\n );\n IERC721Upgradeable(collateralInfo._collateralAddress).approve(\n escrowAddress,\n collateralInfo._tokenId\n );\n collateralEscrow.depositAsset(\n CollateralType.ERC721,\n collateralInfo._collateralAddress,\n collateralInfo._amount,\n collateralInfo._tokenId\n );\n } else if (collateralInfo._collateralType == CollateralType.ERC1155) {\n bytes memory data;\n IERC1155Upgradeable(collateralInfo._collateralAddress)\n .safeTransferFrom(\n borrower,\n address(this),\n collateralInfo._tokenId,\n collateralInfo._amount,\n data\n );\n IERC1155Upgradeable(collateralInfo._collateralAddress)\n .setApprovalForAll(escrowAddress, true);\n collateralEscrow.depositAsset(\n CollateralType.ERC1155,\n collateralInfo._collateralAddress,\n collateralInfo._amount,\n collateralInfo._tokenId\n );\n } else {\n revert(\"Unexpected collateral type\");\n }\n emit CollateralDeposited(\n _bidId,\n collateralInfo._collateralType,\n collateralInfo._collateralAddress,\n collateralInfo._amount,\n collateralInfo._tokenId\n );\n }\n\n /**\n * @notice Withdraws collateral to a given receiver's address.\n * @param _bidId The id of the bid to withdraw collateral for.\n * @param _receiver The address to withdraw the collateral to.\n */\n function _withdraw(uint256 _bidId, address _receiver) internal virtual {\n for (\n uint256 i;\n i < _bidCollaterals[_bidId].collateralAddresses.length();\n i++\n ) {\n // Get collateral info\n Collateral storage collateralInfo = _bidCollaterals[_bidId]\n .collateralInfo[\n _bidCollaterals[_bidId].collateralAddresses.at(i)\n ];\n // Withdraw collateral from escrow and send it to bid lender\n ICollateralEscrowV1(_escrows[_bidId]).withdraw(\n collateralInfo._collateralAddress,\n collateralInfo._amount,\n _receiver\n );\n emit CollateralWithdrawn(\n _bidId,\n collateralInfo._collateralType,\n collateralInfo._collateralAddress,\n collateralInfo._amount,\n collateralInfo._tokenId,\n _receiver\n );\n }\n }\n\n /**\n * @notice Checks the validity of a borrower's collateral balance and commits it to a bid.\n * @param _bidId The id of the associated bid.\n * @param _collateralInfo Additional information about the collateral asset.\n */\n function _commitCollateral(\n uint256 _bidId,\n Collateral memory _collateralInfo\n ) internal virtual {\n CollateralInfo storage collateral = _bidCollaterals[_bidId];\n\n require(\n !collateral.collateralAddresses.contains(\n _collateralInfo._collateralAddress\n ),\n \"Cannot commit multiple collateral with the same address\"\n );\n require(\n _collateralInfo._collateralType != CollateralType.ERC721 ||\n _collateralInfo._amount == 1,\n \"ERC721 collateral must have amount of 1\"\n );\n\n collateral.collateralAddresses.add(_collateralInfo._collateralAddress);\n collateral.collateralInfo[\n _collateralInfo._collateralAddress\n ] = _collateralInfo;\n emit CollateralCommitted(\n _bidId,\n _collateralInfo._collateralType,\n _collateralInfo._collateralAddress,\n _collateralInfo._amount,\n _collateralInfo._tokenId\n );\n }\n\n /**\n * @notice Checks the validity of a borrower's multiple collateral balances.\n * @param _borrowerAddress The address of the borrower holding the collateral.\n * @param _collateralInfo Additional information about the collateral assets.\n * @param _shortCircut if true, will return immediately until an invalid balance\n */\n function _checkBalances(\n address _borrowerAddress,\n Collateral[] memory _collateralInfo,\n bool _shortCircut\n ) internal virtual returns (bool validated_, bool[] memory checks_) {\n checks_ = new bool[](_collateralInfo.length);\n validated_ = true;\n for (uint256 i; i < _collateralInfo.length; i++) {\n bool isValidated = _checkBalance(\n _borrowerAddress,\n _collateralInfo[i]\n );\n checks_[i] = isValidated;\n if (!isValidated) {\n validated_ = false;\n //if short circuit is true, return on the first invalid balance to save execution cycles. Values of checks[] will be invalid/undetermined if shortcircuit is true.\n if (_shortCircut) {\n return (validated_, checks_);\n }\n }\n }\n }\n\n /**\n * @notice Checks the validity of a borrower's single collateral balance.\n * @param _borrowerAddress The address of the borrower holding the collateral.\n * @param _collateralInfo Additional information about the collateral asset.\n * @return validation_ Boolean indicating if the collateral balances were validated.\n */\n function _checkBalance(\n address _borrowerAddress,\n Collateral memory _collateralInfo\n ) internal virtual returns (bool) {\n CollateralType collateralType = _collateralInfo._collateralType;\n\n if (collateralType == CollateralType.ERC20) {\n return\n _collateralInfo._amount <=\n IERC20Upgradeable(_collateralInfo._collateralAddress).balanceOf(\n _borrowerAddress\n );\n } else if (collateralType == CollateralType.ERC721) {\n return\n _borrowerAddress ==\n IERC721Upgradeable(_collateralInfo._collateralAddress).ownerOf(\n _collateralInfo._tokenId\n );\n } else if (collateralType == CollateralType.ERC1155) {\n return\n _collateralInfo._amount <=\n IERC1155Upgradeable(_collateralInfo._collateralAddress)\n .balanceOf(_borrowerAddress, _collateralInfo._tokenId);\n } else {\n return false;\n }\n }\n\n // On NFT Received handlers\n\n function onERC721Received(address, address, uint256, bytes calldata)\n external\n pure\n returns (bytes4)\n {\n return\n bytes4(\n keccak256(\"onERC721Received(address,address,uint256,bytes)\")\n );\n }\n\n function onERC1155Received(\n address,\n address,\n uint256 id,\n uint256 value,\n bytes calldata\n ) external returns (bytes4) {\n return\n bytes4(\n keccak256(\n \"onERC1155Received(address,address,uint256,uint256,bytes)\"\n )\n );\n }\n\n function onERC1155BatchReceived(\n address,\n address,\n uint256[] calldata _ids,\n uint256[] calldata _values,\n bytes calldata\n ) external returns (bytes4) {\n require(\n _ids.length == 1,\n \"Only allowed one asset batch transfer per transaction.\"\n );\n return\n bytes4(\n keccak256(\n \"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"\n )\n );\n }\n}\n" + }, + "contracts/CollateralManagerV2.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\n// Libraries\nimport \"@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol\";\n\n// Interfaces\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\";\nimport \"./interfaces/ICollateralManagerV2.sol\";\nimport \"./interfaces/ITellerV2.sol\";\nimport \"./bundle/TokenStore.sol\";\n\nimport \"./bundle/interfaces/ICollateralBundle.sol\";\n\n/*\n\nThis contract is a token store which stores bundles.\nThe bid id == the bundle id. \n\nIf the bundle exists and is owned by this contract, we know the collateral is held. \n\n*/\n\ncontract CollateralManagerV2 is\n ContextUpgradeable,\n TokenStore,\n ICollateralManagerV2\n{\n /* Storage */\n using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n ITellerV2 public tellerV2;\n\n // bidIds -> collateralBundleId\n mapping(uint256 => uint256) internal _collateralBundleIdForBid;\n\n // bidIds -> collateralBundleInfo\n //this just bridges the gap between submitBid and acceptBid\n mapping(uint256 => ICollateralBundle.CollateralBundleInfo)\n internal _committedBidCollateral;\n\n event CollateralCommitted(\n uint256 _bidId,\n CollateralType _type,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId\n );\n\n event CollateralDeposited(\n uint256 _bidId,\n CollateralType _type,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId\n );\n event CollateralWithdrawn(\n uint256 _bidId,\n CollateralType _type,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId,\n address _recipient\n );\n\n /* Modifiers */\n modifier onlyTellerV2() {\n require(_msgSender() == address(tellerV2), \"Sender not authorized\");\n _;\n }\n\n /* External Functions */\n\n /**\n * @notice Initializes the collateral manager.\n * @param _tellerV2 The address of the protocol.\n */\n function initialize(address _tellerV2) external initializer {\n tellerV2 = ITellerV2(_tellerV2);\n // __Ownable_init_unchained();\n }\n\n /**\n * @notice Checks to see if a bid is backed by collateral.\n * @param _bidId The id of the bid to check.\n */\n\n function isBidCollateralBacked(\n uint256 _bidId\n ) public view virtual returns (bool) {\n return _committedBidCollateral[_bidId].count > 0;\n }\n\n /**\n * @notice Checks the validity of a borrower's multiple collateral balances and commits it to a bid.\n * @param _bidId The id of the associated bid.\n * @param _collateralInfo Additional information about the collateral assets.\n * @return validation_ Boolean indicating if the collateral balances were validated.\n */\n function commitCollateral(\n uint256 _bidId,\n Collateral[] calldata _collateralInfo\n ) external onlyTellerV2 returns (bool validation_) {\n address borrower = tellerV2.getLoanBorrower(_bidId);\n require(borrower != address(0), \"Loan has no borrower\");\n (validation_, ) = checkBalances(borrower, _collateralInfo);\n\n //if the collateral info is valid, call commitCollateral for each one\n if (validation_) {\n for (uint256 i; i < _collateralInfo.length; i++) {\n Collateral memory info = _collateralInfo[i];\n _commitCollateral(_bidId, info);\n }\n }\n }\n\n /**\n * @notice Deploys a new collateral escrow and deposits collateral.\n * @param _bidId The associated bidId of the collateral escrow.\n */\n\n //used to be 'deploy and deposit'\n function depositCollateral(uint256 _bidId) external onlyTellerV2 {\n //if collateral has been committed...\n if (isBidCollateralBacked(_bidId)) {\n Collateral[] memory _committedCollateral = getCollateralInfo(\n _bidId\n );\n\n address borrower = tellerV2.getLoanBorrower(_bidId);\n\n uint256 _bundleId = _storeTokens(borrower, _committedCollateral);\n\n _collateralBundleIdForBid[_bidId] = _bundleId;\n\n uint256 collateralCount = _committedCollateral.length;\n\n for (uint256 i = 0; i < collateralCount; i += 1) {\n emit CollateralDeposited(\n _bidId,\n _committedCollateral[i]._collateralType,\n _committedCollateral[i]._collateralAddress,\n _committedCollateral[i]._amount,\n _committedCollateral[i]._tokenId\n );\n }\n } // is backed\n }\n\n /**\n * @notice Gets the committed collateral info for a given bid id.\n * @param _bidId The bidId to return the collateral info for.\n * @return infos_ The stored collateral info.\n */\n\n function getCollateralInfo(\n uint256 _bidId\n ) public view returns (Collateral[] memory infos_) {\n uint256 count = _committedBidCollateral[_bidId].count;\n infos_ = new Collateral[](count);\n\n for (uint256 i = 0; i < count; i++) {\n infos_[i] = _committedBidCollateral[_bidId].collaterals[i];\n }\n }\n\n /**\n * @notice Gets the collateral asset amount for a given bid id on the TellerV2 contract.\n * @param _bidId The ID of a bid on TellerV2.\n * @param _collateralAddress An address used as collateral.\n * @return amount_ The amount of collateral of type _collateralAddress.\n */\n function getCollateralAmount(\n uint256 _bidId,\n address _collateralAddress\n ) public view returns (uint256 amount_) {\n uint256 bundleId = _collateralBundleIdForBid[_bidId];\n\n Collateral memory token_data = getTokenOfBundle(bundleId, 0); // first slot\n\n if (token_data._collateralAddress != _collateralAddress) return 0; // not as expected\n\n amount_ = token_data._amount;\n }\n\n /**\n * @notice Withdraws deposited collateral of a bid that has been successfully repaid.\n * @param _bidId The id of the bid to withdraw collateral for.\n */\n function withdraw(uint256 _bidId) external {\n BidState bidState = tellerV2.getBidState(_bidId);\n\n require(bidState == BidState.PAID, \"Loan has not been paid\");\n\n _withdraw(_bidId, tellerV2.getLoanBorrower(_bidId));\n }\n\n /**\n * @notice Withdraws deposited collateral of a bid that has been successfully repaid.\n * @param _bidId The id of the bid to withdraw collateral for.\n * @param _recipient The address that will receive the collateral.\n */\n function withdrawForRecipient(uint256 _bidId, address _recipient) external {\n BidState bidState = tellerV2.getBidState(_bidId);\n\n require(bidState == BidState.PAID, \"Loan has not been paid\");\n\n require(\n _msgSender() == tellerV2.getLoanBorrower(_bidId),\n \"Not authorized\"\n );\n\n _withdraw(_bidId, _recipient);\n }\n\n /**\n * @notice Withdraws deposited collateral of a bid that has been CLOSED after being defaulted.\n * @param _bidId The id of the bid to withdraw collateral for.\n */\n function lenderClaimCollateral(uint256 _bidId) external onlyTellerV2 {\n if (isBidCollateralBacked(_bidId)) {\n BidState bidState = tellerV2.getBidState(_bidId);\n\n require(bidState == BidState.CLOSED, \"Loan has not been closed\");\n\n _withdraw(_bidId, tellerV2.getLoanLender(_bidId));\n }\n }\n\n /**\n * @notice Sends the deposited collateral to a liquidator of a bid.\n * @notice Can only be called by the protocol.\n * @param _bidId The id of the liquidated bid.\n * @param _liquidatorAddress The address of the liquidator to send the collateral to.\n */\n function liquidateCollateral(\n uint256 _bidId,\n address _liquidatorAddress\n ) external onlyTellerV2 {\n if (isBidCollateralBacked(_bidId)) {\n BidState bidState = tellerV2.getBidState(_bidId);\n require(\n bidState == BidState.LIQUIDATED,\n \"Loan has not been liquidated\"\n );\n _withdraw(_bidId, _liquidatorAddress);\n }\n }\n\n /**\n * @notice Checks the validity of a borrower's multiple collateral balances.\n * @param _borrowerAddress The address of the borrower holding the collateral.\n * @param _collateralInfo Additional information about the collateral assets.\n */\n function checkBalances(\n address _borrowerAddress,\n Collateral[] calldata _collateralInfo\n ) public view returns (bool validated_, bool[] memory checks_) {\n return _checkBalances(_borrowerAddress, _collateralInfo, false);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Withdraws collateral to a given receiver's address.\n * @param _bidId The id of the bid to withdraw collateral for.\n * @param _receiver The address to withdraw the collateral to.\n */\n function _withdraw(uint256 _bidId, address _receiver) internal virtual {\n uint256 bundleId = _collateralBundleIdForBid[_bidId];\n\n (uint256 count, Collateral[] memory releasedTokens) = _releaseTokens(\n _receiver,\n bundleId\n );\n\n for (uint256 i = 0; i < count; i += 1) {\n emit CollateralWithdrawn(\n _bidId,\n releasedTokens[i]._collateralType,\n releasedTokens[i]._collateralAddress,\n releasedTokens[i]._amount,\n releasedTokens[i]._tokenId,\n _receiver\n );\n }\n }\n\n /**\n * @notice Checks the validity of a borrower's collateral balance and commits it to a bid.\n * @param _bidId The id of the associated bid.\n * @param _collateralInfo Additional information about the collateral asset.\n */\n function _commitCollateral(\n uint256 _bidId,\n Collateral memory _collateralInfo\n ) internal virtual {\n CollateralBundleInfo\n storage committedCollateral = _committedBidCollateral[_bidId];\n\n require(\n _collateralInfo._collateralType != CollateralType.ERC721 ||\n _collateralInfo._amount == 1,\n \"ERC721 collateral must have amount of 1\"\n );\n\n uint256 new_count = committedCollateral.count + 1;\n\n committedCollateral.count = new_count;\n committedCollateral.collaterals[new_count - 1] = Collateral({\n _collateralType: _collateralInfo._collateralType,\n _amount: _collateralInfo._amount,\n _tokenId: _collateralInfo._tokenId,\n _collateralAddress: _collateralInfo._collateralAddress\n });\n\n emit CollateralCommitted(\n _bidId,\n _collateralInfo._collateralType,\n _collateralInfo._collateralAddress,\n _collateralInfo._amount,\n _collateralInfo._tokenId\n );\n }\n\n /**\n * @notice Checks the validity of a borrower's multiple collateral balances.\n * @param _borrowerAddress The address of the borrower holding the collateral.\n * @param _collateralInfo Additional information about the collateral assets.\n * @param _shortCircut if true, will return immediately until an invalid balance\n */\n function _checkBalances(\n address _borrowerAddress,\n Collateral[] memory _collateralInfo,\n bool _shortCircut\n ) internal view virtual returns (bool validated_, bool[] memory checks_) {\n checks_ = new bool[](_collateralInfo.length);\n validated_ = true;\n for (uint256 i; i < _collateralInfo.length; i++) {\n bool isValidated = _checkBalance(\n _borrowerAddress,\n _collateralInfo[i]\n );\n checks_[i] = isValidated;\n if (!isValidated) {\n validated_ = false;\n //if short circuit is true, return on the first invalid balance to save execution cycles. Values of checks[] will be invalid/undetermined if shortcircuit is true.\n if (_shortCircut) {\n return (validated_, checks_);\n }\n }\n }\n }\n\n /**\n * @notice Checks the validity of a borrower's single collateral balance.\n * @param _borrowerAddress The address of the borrower holding the collateral.\n * @param _collateralInfo Additional information about the collateral asset.\n * @return validation_ Boolean indicating if the collateral balances were validated.\n */\n function _checkBalance(\n address _borrowerAddress,\n Collateral memory _collateralInfo\n ) internal view virtual returns (bool) {\n CollateralType collateralType = _collateralInfo._collateralType;\n\n if (collateralType == CollateralType.ERC20) {\n return\n _collateralInfo._amount <=\n IERC20Upgradeable(_collateralInfo._collateralAddress).balanceOf(\n _borrowerAddress\n );\n } else if (collateralType == CollateralType.ERC721) {\n return\n _borrowerAddress ==\n IERC721Upgradeable(_collateralInfo._collateralAddress).ownerOf(\n _collateralInfo._tokenId\n );\n } else if (collateralType == CollateralType.ERC1155) {\n return\n _collateralInfo._amount <=\n IERC1155Upgradeable(_collateralInfo._collateralAddress)\n .balanceOf(_borrowerAddress, _collateralInfo._tokenId);\n } else {\n return false;\n }\n }\n\n // On NFT Received handlers\n\n function onERC721Received(\n address,\n address,\n uint256,\n bytes memory\n ) public pure override returns (bytes4) {\n return\n bytes4(\n keccak256(\"onERC721Received(address,address,uint256,bytes)\")\n );\n }\n\n function onERC1155Received(\n address,\n address,\n uint256 id,\n uint256 value,\n bytes memory\n ) public override returns (bytes4) {\n return\n bytes4(\n keccak256(\n \"onERC1155Received(address,address,uint256,uint256,bytes)\"\n )\n );\n }\n\n function onERC1155BatchReceived(\n address,\n address,\n uint256[] memory _ids,\n uint256[] memory _values,\n bytes memory\n ) public override returns (bytes4) {\n require(\n _ids.length == 1,\n \"Only allowed one asset batch transfer per transaction.\"\n );\n return\n bytes4(\n keccak256(\n \"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"\n )\n );\n }\n}\n" + }, + "contracts/EAS/TellerAS.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"../Types.sol\";\nimport \"../interfaces/IEAS.sol\";\nimport \"../interfaces/IASRegistry.sol\";\n\n/**\n * @title TellerAS - Teller Attestation Service - based on EAS - Ethereum Attestation Service\n */\ncontract TellerAS is IEAS {\n error AccessDenied();\n error AlreadyRevoked();\n error InvalidAttestation();\n error InvalidExpirationTime();\n error InvalidOffset();\n error InvalidRegistry();\n error InvalidSchema();\n error InvalidVerifier();\n error NotFound();\n error NotPayable();\n\n string public constant VERSION = \"0.8\";\n\n // A terminator used when concatenating and hashing multiple fields.\n string private constant HASH_TERMINATOR = \"@\";\n\n // The AS global registry.\n IASRegistry private immutable _asRegistry;\n\n // The EIP712 verifier used to verify signed attestations.\n IEASEIP712Verifier private immutable _eip712Verifier;\n\n // A mapping between attestations and their related attestations.\n mapping(bytes32 => bytes32[]) private _relatedAttestations;\n\n // A mapping between an account and its received attestations.\n mapping(address => mapping(bytes32 => bytes32[]))\n private _receivedAttestations;\n\n // A mapping between an account and its sent attestations.\n mapping(address => mapping(bytes32 => bytes32[])) private _sentAttestations;\n\n // A mapping between a schema and its attestations.\n mapping(bytes32 => bytes32[]) private _schemaAttestations;\n\n // The global mapping between attestations and their UUIDs.\n mapping(bytes32 => Attestation) private _db;\n\n // The global counter for the total number of attestations.\n uint256 private _attestationsCount;\n\n bytes32 private _lastUUID;\n\n /**\n * @dev Creates a new EAS instance.\n *\n * @param registry The address of the global AS registry.\n * @param verifier The address of the EIP712 verifier.\n */\n constructor(IASRegistry registry, IEASEIP712Verifier verifier) {\n if (address(registry) == address(0x0)) {\n revert InvalidRegistry();\n }\n\n if (address(verifier) == address(0x0)) {\n revert InvalidVerifier();\n }\n\n _asRegistry = registry;\n _eip712Verifier = verifier;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getASRegistry() external view override returns (IASRegistry) {\n return _asRegistry;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getEIP712Verifier()\n external\n view\n override\n returns (IEASEIP712Verifier)\n {\n return _eip712Verifier;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getAttestationsCount() external view override returns (uint256) {\n return _attestationsCount;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function attest(\n address recipient,\n bytes32 schema,\n uint256 expirationTime,\n bytes32 refUUID,\n bytes calldata data\n ) public payable virtual override returns (bytes32) {\n return\n _attest(\n recipient,\n schema,\n expirationTime,\n refUUID,\n data,\n msg.sender\n );\n }\n\n /**\n * @inheritdoc IEAS\n */\n function attestByDelegation(\n address recipient,\n bytes32 schema,\n uint256 expirationTime,\n bytes32 refUUID,\n bytes calldata data,\n address attester,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public payable virtual override returns (bytes32) {\n _eip712Verifier.attest(\n recipient,\n schema,\n expirationTime,\n refUUID,\n data,\n attester,\n v,\n r,\n s\n );\n\n return\n _attest(recipient, schema, expirationTime, refUUID, data, attester);\n }\n\n /**\n * @inheritdoc IEAS\n */\n function revoke(bytes32 uuid) public virtual override {\n return _revoke(uuid, msg.sender);\n }\n\n /**\n * @inheritdoc IEAS\n */\n function revokeByDelegation(\n bytes32 uuid,\n address attester,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n _eip712Verifier.revoke(uuid, attester, v, r, s);\n\n _revoke(uuid, attester);\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getAttestation(bytes32 uuid)\n external\n view\n override\n returns (Attestation memory)\n {\n return _db[uuid];\n }\n\n /**\n * @inheritdoc IEAS\n */\n function isAttestationValid(bytes32 uuid)\n public\n view\n override\n returns (bool)\n {\n return _db[uuid].uuid != 0;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function isAttestationActive(bytes32 uuid)\n public\n view\n virtual\n override\n returns (bool)\n {\n return\n isAttestationValid(uuid) &&\n _db[uuid].expirationTime >= block.timestamp &&\n _db[uuid].revocationTime == 0;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getReceivedAttestationUUIDs(\n address recipient,\n bytes32 schema,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view override returns (bytes32[] memory) {\n return\n _sliceUUIDs(\n _receivedAttestations[recipient][schema],\n start,\n length,\n reverseOrder\n );\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getReceivedAttestationUUIDsCount(address recipient, bytes32 schema)\n external\n view\n override\n returns (uint256)\n {\n return _receivedAttestations[recipient][schema].length;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getSentAttestationUUIDs(\n address attester,\n bytes32 schema,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view override returns (bytes32[] memory) {\n return\n _sliceUUIDs(\n _sentAttestations[attester][schema],\n start,\n length,\n reverseOrder\n );\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getSentAttestationUUIDsCount(address recipient, bytes32 schema)\n external\n view\n override\n returns (uint256)\n {\n return _sentAttestations[recipient][schema].length;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getRelatedAttestationUUIDs(\n bytes32 uuid,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view override returns (bytes32[] memory) {\n return\n _sliceUUIDs(\n _relatedAttestations[uuid],\n start,\n length,\n reverseOrder\n );\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getRelatedAttestationUUIDsCount(bytes32 uuid)\n external\n view\n override\n returns (uint256)\n {\n return _relatedAttestations[uuid].length;\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getSchemaAttestationUUIDs(\n bytes32 schema,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view override returns (bytes32[] memory) {\n return\n _sliceUUIDs(\n _schemaAttestations[schema],\n start,\n length,\n reverseOrder\n );\n }\n\n /**\n * @inheritdoc IEAS\n */\n function getSchemaAttestationUUIDsCount(bytes32 schema)\n external\n view\n override\n returns (uint256)\n {\n return _schemaAttestations[schema].length;\n }\n\n /**\n * @dev Attests to a specific AS.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n * @param expirationTime The expiration time of the attestation.\n * @param refUUID An optional related attestation's UUID.\n * @param data Additional custom data.\n * @param attester The attesting account.\n *\n * @return The UUID of the new attestation.\n */\n function _attest(\n address recipient,\n bytes32 schema,\n uint256 expirationTime,\n bytes32 refUUID,\n bytes calldata data,\n address attester\n ) private returns (bytes32) {\n if (expirationTime <= block.timestamp) {\n revert InvalidExpirationTime();\n }\n\n IASRegistry.ASRecord memory asRecord = _asRegistry.getAS(schema);\n if (asRecord.uuid == EMPTY_UUID) {\n revert InvalidSchema();\n }\n\n IASResolver resolver = asRecord.resolver;\n if (address(resolver) != address(0x0)) {\n if (msg.value != 0 && !resolver.isPayable()) {\n revert NotPayable();\n }\n\n if (\n !resolver.resolve{ value: msg.value }(\n recipient,\n asRecord.schema,\n data,\n expirationTime,\n attester\n )\n ) {\n revert InvalidAttestation();\n }\n }\n\n Attestation memory attestation = Attestation({\n uuid: EMPTY_UUID,\n schema: schema,\n recipient: recipient,\n attester: attester,\n time: block.timestamp,\n expirationTime: expirationTime,\n revocationTime: 0,\n refUUID: refUUID,\n data: data\n });\n\n _lastUUID = _getUUID(attestation);\n attestation.uuid = _lastUUID;\n\n _receivedAttestations[recipient][schema].push(_lastUUID);\n _sentAttestations[attester][schema].push(_lastUUID);\n _schemaAttestations[schema].push(_lastUUID);\n\n _db[_lastUUID] = attestation;\n _attestationsCount++;\n\n if (refUUID != 0) {\n if (!isAttestationValid(refUUID)) {\n revert NotFound();\n }\n\n _relatedAttestations[refUUID].push(_lastUUID);\n }\n\n emit Attested(recipient, attester, _lastUUID, schema);\n\n return _lastUUID;\n }\n\n function getLastUUID() external view returns (bytes32) {\n return _lastUUID;\n }\n\n /**\n * @dev Revokes an existing attestation to a specific AS.\n *\n * @param uuid The UUID of the attestation to revoke.\n * @param attester The attesting account.\n */\n function _revoke(bytes32 uuid, address attester) private {\n Attestation storage attestation = _db[uuid];\n if (attestation.uuid == EMPTY_UUID) {\n revert NotFound();\n }\n\n if (attestation.attester != attester) {\n revert AccessDenied();\n }\n\n if (attestation.revocationTime != 0) {\n revert AlreadyRevoked();\n }\n\n attestation.revocationTime = block.timestamp;\n\n emit Revoked(attestation.recipient, attester, uuid, attestation.schema);\n }\n\n /**\n * @dev Calculates a UUID for a given attestation.\n *\n * @param attestation The input attestation.\n *\n * @return Attestation UUID.\n */\n function _getUUID(Attestation memory attestation)\n private\n view\n returns (bytes32)\n {\n return\n keccak256(\n abi.encodePacked(\n attestation.schema,\n attestation.recipient,\n attestation.attester,\n attestation.time,\n attestation.expirationTime,\n attestation.data,\n HASH_TERMINATOR,\n _attestationsCount\n )\n );\n }\n\n /**\n * @dev Returns a slice in an array of attestation UUIDs.\n *\n * @param uuids The array of attestation UUIDs.\n * @param start The offset to start from.\n * @param length The number of total members to retrieve.\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\n *\n * @return An array of attestation UUIDs.\n */\n function _sliceUUIDs(\n bytes32[] memory uuids,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) private pure returns (bytes32[] memory) {\n uint256 attestationsLength = uuids.length;\n if (attestationsLength == 0) {\n return new bytes32[](0);\n }\n\n if (start >= attestationsLength) {\n revert InvalidOffset();\n }\n\n uint256 len = length;\n if (attestationsLength < start + length) {\n len = attestationsLength - start;\n }\n\n bytes32[] memory res = new bytes32[](len);\n\n for (uint256 i = 0; i < len; ++i) {\n res[i] = uuids[\n reverseOrder ? attestationsLength - (start + i + 1) : start + i\n ];\n }\n\n return res;\n }\n}\n" + }, + "contracts/EAS/TellerASResolver.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"../interfaces/IASResolver.sol\";\n\n/**\n * @title A base resolver contract\n */\nabstract contract TellerASResolver is IASResolver {\n error NotPayable();\n\n function isPayable() public pure virtual override returns (bool) {\n return false;\n }\n\n receive() external payable virtual {\n if (!isPayable()) {\n revert NotPayable();\n }\n }\n}\n" + }, + "contracts/ERC2771ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (metatx/ERC2771Context.sol)\n\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev Context variant with ERC2771 support.\n * @dev This is modified from the OZ library to remove the gap of storage variables at the end.\n */\nabstract contract ERC2771ContextUpgradeable is\n Initializable,\n ContextUpgradeable\n{\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address private immutable _trustedForwarder;\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address trustedForwarder) {\n _trustedForwarder = trustedForwarder;\n }\n\n function isTrustedForwarder(address forwarder)\n public\n view\n virtual\n returns (bool)\n {\n return forwarder == _trustedForwarder;\n }\n\n function _msgSender()\n internal\n view\n virtual\n override\n returns (address sender)\n {\n if (isTrustedForwarder(msg.sender)) {\n // The assembly code is more direct than the Solidity version using `abi.decode`.\n assembly {\n sender := shr(96, calldataload(sub(calldatasize(), 20)))\n }\n } else {\n return super._msgSender();\n }\n }\n\n function _msgData()\n internal\n view\n virtual\n override\n returns (bytes calldata)\n {\n if (isTrustedForwarder(msg.sender)) {\n return msg.data[:msg.data.length - 20];\n } else {\n return super._msgData();\n }\n }\n}\n" + }, + "contracts/interfaces/aave/DataTypes.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nlibrary DataTypes {\n struct ReserveData {\n //stores the reserve configuration\n ReserveConfigurationMap configuration;\n //the liquidity index. Expressed in ray\n uint128 liquidityIndex;\n //the current supply rate. Expressed in ray\n uint128 currentLiquidityRate;\n //variable borrow index. Expressed in ray\n uint128 variableBorrowIndex;\n //the current variable borrow rate. Expressed in ray\n uint128 currentVariableBorrowRate;\n //the current stable borrow rate. Expressed in ray\n uint128 currentStableBorrowRate;\n //timestamp of last update\n uint40 lastUpdateTimestamp;\n //the id of the reserve. Represents the position in the list of the active reserves\n uint16 id;\n //aToken address\n address aTokenAddress;\n //stableDebtToken address\n address stableDebtTokenAddress;\n //variableDebtToken address\n address variableDebtTokenAddress;\n //address of the interest rate strategy\n address interestRateStrategyAddress;\n //the current treasury balance, scaled\n uint128 accruedToTreasury;\n //the outstanding unbacked aTokens minted through the bridging feature\n uint128 unbacked;\n //the outstanding debt borrowed against this asset in isolation mode\n uint128 isolationModeTotalDebt;\n }\n\n struct ReserveConfigurationMap {\n //bit 0-15: LTV\n //bit 16-31: Liq. threshold\n //bit 32-47: Liq. bonus\n //bit 48-55: Decimals\n //bit 56: reserve is active\n //bit 57: reserve is frozen\n //bit 58: borrowing is enabled\n //bit 59: stable rate borrowing enabled\n //bit 60: asset is paused\n //bit 61: borrowing in isolation mode is enabled\n //bit 62: siloed borrowing enabled\n //bit 63: flashloaning enabled\n //bit 64-79: reserve factor\n //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap\n //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap\n //bit 152-167 liquidation protocol fee\n //bit 168-175 eMode category\n //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled\n //bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals\n //bit 252-255 unused\n\n uint256 data;\n }\n\n struct UserConfigurationMap {\n /**\n * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.\n * The first bit indicates if an asset is used as collateral by the user, the second whether an\n * asset is borrowed by the user.\n */\n uint256 data;\n }\n\n struct EModeCategory {\n // each eMode category has a custom ltv and liquidation threshold\n uint16 ltv;\n uint16 liquidationThreshold;\n uint16 liquidationBonus;\n // each eMode category may or may not have a custom oracle to override the individual assets price oracles\n address priceSource;\n string label;\n }\n\n enum InterestRateMode {\n NONE,\n STABLE,\n VARIABLE\n }\n\n struct ReserveCache {\n uint256 currScaledVariableDebt;\n uint256 nextScaledVariableDebt;\n uint256 currPrincipalStableDebt;\n uint256 currAvgStableBorrowRate;\n uint256 currTotalStableDebt;\n uint256 nextAvgStableBorrowRate;\n uint256 nextTotalStableDebt;\n uint256 currLiquidityIndex;\n uint256 nextLiquidityIndex;\n uint256 currVariableBorrowIndex;\n uint256 nextVariableBorrowIndex;\n uint256 currLiquidityRate;\n uint256 currVariableBorrowRate;\n uint256 reserveFactor;\n ReserveConfigurationMap reserveConfiguration;\n address aTokenAddress;\n address stableDebtTokenAddress;\n address variableDebtTokenAddress;\n uint40 reserveLastUpdateTimestamp;\n uint40 stableDebtLastUpdateTimestamp;\n }\n\n struct ExecuteLiquidationCallParams {\n uint256 reservesCount;\n uint256 debtToCover;\n address collateralAsset;\n address debtAsset;\n address user;\n bool receiveAToken;\n address priceOracle;\n uint8 userEModeCategory;\n address priceOracleSentinel;\n }\n\n struct ExecuteSupplyParams {\n address asset;\n uint256 amount;\n address onBehalfOf;\n uint16 referralCode;\n }\n\n struct ExecuteBorrowParams {\n address asset;\n address user;\n address onBehalfOf;\n uint256 amount;\n InterestRateMode interestRateMode;\n uint16 referralCode;\n bool releaseUnderlying;\n uint256 maxStableRateBorrowSizePercent;\n uint256 reservesCount;\n address oracle;\n uint8 userEModeCategory;\n address priceOracleSentinel;\n }\n\n struct ExecuteRepayParams {\n address asset;\n uint256 amount;\n InterestRateMode interestRateMode;\n address onBehalfOf;\n bool useATokens;\n }\n\n struct ExecuteWithdrawParams {\n address asset;\n uint256 amount;\n address to;\n uint256 reservesCount;\n address oracle;\n uint8 userEModeCategory;\n }\n\n struct ExecuteSetUserEModeParams {\n uint256 reservesCount;\n address oracle;\n uint8 categoryId;\n }\n\n struct FinalizeTransferParams {\n address asset;\n address from;\n address to;\n uint256 amount;\n uint256 balanceFromBefore;\n uint256 balanceToBefore;\n uint256 reservesCount;\n address oracle;\n uint8 fromEModeCategory;\n }\n\n struct FlashloanParams {\n address receiverAddress;\n address[] assets;\n uint256[] amounts;\n uint256[] interestRateModes;\n address onBehalfOf;\n bytes params;\n uint16 referralCode;\n uint256 flashLoanPremiumToProtocol;\n uint256 flashLoanPremiumTotal;\n uint256 maxStableRateBorrowSizePercent;\n uint256 reservesCount;\n address addressesProvider;\n uint8 userEModeCategory;\n bool isAuthorizedFlashBorrower;\n }\n\n struct FlashloanSimpleParams {\n address receiverAddress;\n address asset;\n uint256 amount;\n bytes params;\n uint16 referralCode;\n uint256 flashLoanPremiumToProtocol;\n uint256 flashLoanPremiumTotal;\n }\n\n struct FlashLoanRepaymentParams {\n uint256 amount;\n uint256 totalPremium;\n uint256 flashLoanPremiumToProtocol;\n address asset;\n address receiverAddress;\n uint16 referralCode;\n }\n\n struct CalculateUserAccountDataParams {\n UserConfigurationMap userConfig;\n uint256 reservesCount;\n address user;\n address oracle;\n uint8 userEModeCategory;\n }\n\n struct ValidateBorrowParams {\n ReserveCache reserveCache;\n UserConfigurationMap userConfig;\n address asset;\n address userAddress;\n uint256 amount;\n InterestRateMode interestRateMode;\n uint256 maxStableLoanPercent;\n uint256 reservesCount;\n address oracle;\n uint8 userEModeCategory;\n address priceOracleSentinel;\n bool isolationModeActive;\n address isolationModeCollateralAddress;\n uint256 isolationModeDebtCeiling;\n }\n\n struct ValidateLiquidationCallParams {\n ReserveCache debtReserveCache;\n uint256 totalDebt;\n uint256 healthFactor;\n address priceOracleSentinel;\n }\n\n struct CalculateInterestRatesParams {\n uint256 unbacked;\n uint256 liquidityAdded;\n uint256 liquidityTaken;\n uint256 totalStableDebt;\n uint256 totalVariableDebt;\n uint256 averageStableBorrowRate;\n uint256 reserveFactor;\n address reserve;\n address aToken;\n }\n\n struct InitReserveParams {\n address asset;\n address aTokenAddress;\n address stableDebtAddress;\n address variableDebtAddress;\n address interestRateStrategyAddress;\n uint16 reservesCount;\n uint16 maxNumberReserves;\n }\n}\n" + }, + "contracts/interfaces/aave/IFlashLoanSimpleReceiver.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.0;\n\nimport { IPoolAddressesProvider } from \"./IPoolAddressesProvider.sol\";\nimport { IPool } from \"./IPool.sol\";\n\n/**\n * @title IFlashLoanSimpleReceiver\n * @author Aave\n * @notice Defines the basic interface of a flashloan-receiver contract.\n * @dev Implement this interface to develop a flashloan-compatible flashLoanReceiver contract\n */\ninterface IFlashLoanSimpleReceiver {\n /**\n * @notice Executes an operation after receiving the flash-borrowed asset\n * @dev Ensure that the contract can return the debt + premium, e.g., has\n * enough funds to repay and has approved the Pool to pull the total amount\n * @param asset The address of the flash-borrowed asset\n * @param amount The amount of the flash-borrowed asset\n * @param premium The fee of the flash-borrowed asset\n * @param initiator The address of the flashloan initiator\n * @param params The byte-encoded params passed when initiating the flashloan\n * @return True if the execution of the operation succeeds, false otherwise\n */\n function executeOperation(\n address asset,\n uint256 amount,\n uint256 premium,\n address initiator,\n bytes calldata params\n ) external returns (bool);\n\n function ADDRESSES_PROVIDER()\n external\n view\n returns (IPoolAddressesProvider);\n\n function POOL() external view returns (IPool);\n}\n" + }, + "contracts/interfaces/aave/IPool.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.0;\n\nimport { IPoolAddressesProvider } from \"./IPoolAddressesProvider.sol\";\nimport { DataTypes } from \"./DataTypes.sol\";\n\n/**\n * @title IPool\n * @author Aave\n * @notice Defines the basic interface for an Aave Pool.\n */\ninterface IPool {\n /**\n * @dev Emitted on mintUnbacked()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The address initiating the supply\n * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens\n * @param amount The amount of supplied assets\n * @param referralCode The referral code used\n */\n event MintUnbacked(\n address indexed reserve,\n address user,\n address indexed onBehalfOf,\n uint256 amount,\n uint16 indexed referralCode\n );\n\n /**\n * @dev Emitted on backUnbacked()\n * @param reserve The address of the underlying asset of the reserve\n * @param backer The address paying for the backing\n * @param amount The amount added as backing\n * @param fee The amount paid in fees\n */\n event BackUnbacked(\n address indexed reserve,\n address indexed backer,\n uint256 amount,\n uint256 fee\n );\n\n /**\n * @dev Emitted on supply()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The address initiating the supply\n * @param onBehalfOf The beneficiary of the supply, receiving the aTokens\n * @param amount The amount supplied\n * @param referralCode The referral code used\n */\n event Supply(\n address indexed reserve,\n address user,\n address indexed onBehalfOf,\n uint256 amount,\n uint16 indexed referralCode\n );\n\n /**\n * @dev Emitted on withdraw()\n * @param reserve The address of the underlying asset being withdrawn\n * @param user The address initiating the withdrawal, owner of aTokens\n * @param to The address that will receive the underlying\n * @param amount The amount to be withdrawn\n */\n event Withdraw(\n address indexed reserve,\n address indexed user,\n address indexed to,\n uint256 amount\n );\n\n /**\n * @dev Emitted on borrow() and flashLoan() when debt needs to be opened\n * @param reserve The address of the underlying asset being borrowed\n * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just\n * initiator of the transaction on flashLoan()\n * @param onBehalfOf The address that will be getting the debt\n * @param amount The amount borrowed out\n * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable\n * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray\n * @param referralCode The referral code used\n */\n event Borrow(\n address indexed reserve,\n address user,\n address indexed onBehalfOf,\n uint256 amount,\n DataTypes.InterestRateMode interestRateMode,\n uint256 borrowRate,\n uint16 indexed referralCode\n );\n\n /**\n * @dev Emitted on repay()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The beneficiary of the repayment, getting his debt reduced\n * @param repayer The address of the user initiating the repay(), providing the funds\n * @param amount The amount repaid\n * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly\n */\n event Repay(\n address indexed reserve,\n address indexed user,\n address indexed repayer,\n uint256 amount,\n bool useATokens\n );\n\n /**\n * @dev Emitted on swapBorrowRateMode()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The address of the user swapping his rate mode\n * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable\n */\n event SwapBorrowRateMode(\n address indexed reserve,\n address indexed user,\n DataTypes.InterestRateMode interestRateMode\n );\n\n /**\n * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets\n * @param asset The address of the underlying asset of the reserve\n * @param totalDebt The total isolation mode debt for the reserve\n */\n event IsolationModeTotalDebtUpdated(\n address indexed asset,\n uint256 totalDebt\n );\n\n /**\n * @dev Emitted when the user selects a certain asset category for eMode\n * @param user The address of the user\n * @param categoryId The category id\n */\n event UserEModeSet(address indexed user, uint8 categoryId);\n\n /**\n * @dev Emitted on setUserUseReserveAsCollateral()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The address of the user enabling the usage as collateral\n */\n event ReserveUsedAsCollateralEnabled(\n address indexed reserve,\n address indexed user\n );\n\n /**\n * @dev Emitted on setUserUseReserveAsCollateral()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The address of the user enabling the usage as collateral\n */\n event ReserveUsedAsCollateralDisabled(\n address indexed reserve,\n address indexed user\n );\n\n /**\n * @dev Emitted on rebalanceStableBorrowRate()\n * @param reserve The address of the underlying asset of the reserve\n * @param user The address of the user for which the rebalance has been executed\n */\n event RebalanceStableBorrowRate(\n address indexed reserve,\n address indexed user\n );\n\n /**\n * @dev Emitted on flashLoan()\n * @param target The address of the flash loan receiver contract\n * @param initiator The address initiating the flash loan\n * @param asset The address of the asset being flash borrowed\n * @param amount The amount flash borrowed\n * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt\n * @param premium The fee flash borrowed\n * @param referralCode The referral code used\n */\n event FlashLoan(\n address indexed target,\n address initiator,\n address indexed asset,\n uint256 amount,\n DataTypes.InterestRateMode interestRateMode,\n uint256 premium,\n uint16 indexed referralCode\n );\n\n /**\n * @dev Emitted when a borrower is liquidated.\n * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation\n * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation\n * @param user The address of the borrower getting liquidated\n * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover\n * @param liquidatedCollateralAmount The amount of collateral received by the liquidator\n * @param liquidator The address of the liquidator\n * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants\n * to receive the underlying collateral asset directly\n */\n event LiquidationCall(\n address indexed collateralAsset,\n address indexed debtAsset,\n address indexed user,\n uint256 debtToCover,\n uint256 liquidatedCollateralAmount,\n address liquidator,\n bool receiveAToken\n );\n\n /**\n * @dev Emitted when the state of a reserve is updated.\n * @param reserve The address of the underlying asset of the reserve\n * @param liquidityRate The next liquidity rate\n * @param stableBorrowRate The next stable borrow rate\n * @param variableBorrowRate The next variable borrow rate\n * @param liquidityIndex The next liquidity index\n * @param variableBorrowIndex The next variable borrow index\n */\n event ReserveDataUpdated(\n address indexed reserve,\n uint256 liquidityRate,\n uint256 stableBorrowRate,\n uint256 variableBorrowRate,\n uint256 liquidityIndex,\n uint256 variableBorrowIndex\n );\n\n /**\n * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.\n * @param reserve The address of the reserve\n * @param amountMinted The amount minted to the treasury\n */\n event MintedToTreasury(address indexed reserve, uint256 amountMinted);\n\n /**\n * @notice Mints an `amount` of aTokens to the `onBehalfOf`\n * @param asset The address of the underlying asset to mint\n * @param amount The amount to mint\n * @param onBehalfOf The address that will receive the aTokens\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n */\n function mintUnbacked(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode\n ) external;\n\n /**\n * @notice Back the current unbacked underlying with `amount` and pay `fee`.\n * @param asset The address of the underlying asset to back\n * @param amount The amount to back\n * @param fee The amount paid in fees\n * @return The backed amount\n */\n function backUnbacked(address asset, uint256 amount, uint256 fee)\n external\n returns (uint256);\n\n /**\n * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n * - E.g. User supplies 100 USDC and gets in return 100 aUSDC\n * @param asset The address of the underlying asset to supply\n * @param amount The amount to be supplied\n * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n * is a different wallet\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n */\n function supply(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode\n ) external;\n\n /**\n * @notice Supply with transfer approval of asset to be supplied done via permit function\n * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713\n * @param asset The address of the underlying asset to supply\n * @param amount The amount to be supplied\n * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n * is a different wallet\n * @param deadline The deadline timestamp that the permit is valid\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n * @param permitV The V parameter of ERC712 permit sig\n * @param permitR The R parameter of ERC712 permit sig\n * @param permitS The S parameter of ERC712 permit sig\n */\n function supplyWithPermit(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode,\n uint256 deadline,\n uint8 permitV,\n bytes32 permitR,\n bytes32 permitS\n ) external;\n\n /**\n * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned\n * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC\n * @param asset The address of the underlying asset to withdraw\n * @param amount The underlying amount to be withdrawn\n * - Send the value type(uint256).max in order to withdraw the whole aToken balance\n * @param to The address that will receive the underlying, same as msg.sender if the user\n * wants to receive it on his own wallet, or a different address if the beneficiary is a\n * different wallet\n * @return The final amount withdrawn\n */\n function withdraw(address asset, uint256 amount, address to)\n external\n returns (uint256);\n\n /**\n * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower\n * already supplied enough collateral, or he was given enough allowance by a credit delegator on the\n * corresponding debt token (StableDebtToken or VariableDebtToken)\n * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet\n * and 100 stable/variable debt tokens, depending on the `interestRateMode`\n * @param asset The address of the underlying asset to borrow\n * @param amount The amount to be borrowed\n * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable\n * @param referralCode The code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself\n * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator\n * if he has been given credit delegation allowance\n */\n function borrow(\n address asset,\n uint256 amount,\n uint256 interestRateMode,\n uint16 referralCode,\n address onBehalfOf\n ) external;\n\n /**\n * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned\n * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address\n * @param asset The address of the borrowed underlying asset previously borrowed\n * @param amount The amount to repay\n * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`\n * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable\n * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the\n * user calling the function if he wants to reduce/remove his own debt, or the address of any other\n * other borrower whose debt should be removed\n * @return The final amount repaid\n */\n function repay(\n address asset,\n uint256 amount,\n uint256 interestRateMode,\n address onBehalfOf\n ) external returns (uint256);\n\n /**\n * @notice Repay with transfer approval of asset to be repaid done via permit function\n * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713\n * @param asset The address of the borrowed underlying asset previously borrowed\n * @param amount The amount to repay\n * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`\n * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable\n * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the\n * user calling the function if he wants to reduce/remove his own debt, or the address of any other\n * other borrower whose debt should be removed\n * @param deadline The deadline timestamp that the permit is valid\n * @param permitV The V parameter of ERC712 permit sig\n * @param permitR The R parameter of ERC712 permit sig\n * @param permitS The S parameter of ERC712 permit sig\n * @return The final amount repaid\n */\n function repayWithPermit(\n address asset,\n uint256 amount,\n uint256 interestRateMode,\n address onBehalfOf,\n uint256 deadline,\n uint8 permitV,\n bytes32 permitR,\n bytes32 permitS\n ) external returns (uint256);\n\n /**\n * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the\n * equivalent debt tokens\n * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens\n * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken\n * balance is not enough to cover the whole debt\n * @param asset The address of the borrowed underlying asset previously borrowed\n * @param amount The amount to repay\n * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`\n * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable\n * @return The final amount repaid\n */\n function repayWithATokens(\n address asset,\n uint256 amount,\n uint256 interestRateMode\n ) external returns (uint256);\n\n /**\n * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa\n * @param asset The address of the underlying asset borrowed\n * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable\n */\n function swapBorrowRateMode(address asset, uint256 interestRateMode)\n external;\n\n /**\n * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.\n * - Users can be rebalanced if the following conditions are satisfied:\n * 1. Usage ratio is above 95%\n * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too\n * much has been borrowed at a stable rate and suppliers are not earning enough\n * @param asset The address of the underlying asset borrowed\n * @param user The address of the user to be rebalanced\n */\n function rebalanceStableBorrowRate(address asset, address user) external;\n\n /**\n * @notice Allows suppliers to enable/disable a specific supplied asset as collateral\n * @param asset The address of the underlying asset supplied\n * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise\n */\n function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)\n external;\n\n /**\n * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1\n * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives\n * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk\n * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation\n * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation\n * @param user The address of the borrower getting liquidated\n * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover\n * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants\n * to receive the underlying collateral asset directly\n */\n function liquidationCall(\n address collateralAsset,\n address debtAsset,\n address user,\n uint256 debtToCover,\n bool receiveAToken\n ) external;\n\n /**\n * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,\n * as long as the amount taken plus a fee is returned.\n * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept\n * into consideration. For further details please visit https://docs.aave.com/developers/\n * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface\n * @param assets The addresses of the assets being flash-borrowed\n * @param amounts The amounts of the assets being flash-borrowed\n * @param interestRateModes Types of the debt to open if the flash loan is not returned:\n * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver\n * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address\n * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address\n * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2\n * @param params Variadic packed params to pass to the receiver as extra information\n * @param referralCode The code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n */\n function flashLoan(\n address receiverAddress,\n address[] calldata assets,\n uint256[] calldata amounts,\n uint256[] calldata interestRateModes,\n address onBehalfOf,\n bytes calldata params,\n uint16 referralCode\n ) external;\n\n /**\n * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,\n * as long as the amount taken plus a fee is returned.\n * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept\n * into consideration. For further details please visit https://docs.aave.com/developers/\n * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface\n * @param asset The address of the asset being flash-borrowed\n * @param amount The amount of the asset being flash-borrowed\n * @param params Variadic packed params to pass to the receiver as extra information\n * @param referralCode The code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n */\n function flashLoanSimple(\n address receiverAddress,\n address asset,\n uint256 amount,\n bytes calldata params,\n uint16 referralCode\n ) external;\n\n /**\n * @notice Returns the user account data across all the reserves\n * @param user The address of the user\n * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed\n * @return totalDebtBase The total debt of the user in the base currency used by the price feed\n * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed\n * @return currentLiquidationThreshold The liquidation threshold of the user\n * @return ltv The loan to value of The user\n * @return healthFactor The current health factor of the user\n */\n function getUserAccountData(address user)\n external\n view\n returns (\n uint256 totalCollateralBase,\n uint256 totalDebtBase,\n uint256 availableBorrowsBase,\n uint256 currentLiquidationThreshold,\n uint256 ltv,\n uint256 healthFactor\n );\n\n /**\n * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an\n * interest rate strategy\n * @dev Only callable by the PoolConfigurator contract\n * @param asset The address of the underlying asset of the reserve\n * @param aTokenAddress The address of the aToken that will be assigned to the reserve\n * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve\n * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve\n * @param interestRateStrategyAddress The address of the interest rate strategy contract\n */\n function initReserve(\n address asset,\n address aTokenAddress,\n address stableDebtAddress,\n address variableDebtAddress,\n address interestRateStrategyAddress\n ) external;\n\n /**\n * @notice Drop a reserve\n * @dev Only callable by the PoolConfigurator contract\n * @param asset The address of the underlying asset of the reserve\n */\n function dropReserve(address asset) external;\n\n /**\n * @notice Updates the address of the interest rate strategy contract\n * @dev Only callable by the PoolConfigurator contract\n * @param asset The address of the underlying asset of the reserve\n * @param rateStrategyAddress The address of the interest rate strategy contract\n */\n function setReserveInterestRateStrategyAddress(\n address asset,\n address rateStrategyAddress\n ) external;\n\n /**\n * @notice Sets the configuration bitmap of the reserve as a whole\n * @dev Only callable by the PoolConfigurator contract\n * @param asset The address of the underlying asset of the reserve\n * @param configuration The new configuration bitmap\n */\n function setConfiguration(\n address asset,\n DataTypes.ReserveConfigurationMap calldata configuration\n ) external;\n\n /**\n * @notice Returns the configuration of the reserve\n * @param asset The address of the underlying asset of the reserve\n * @return The configuration of the reserve\n */\n function getConfiguration(address asset)\n external\n view\n returns (DataTypes.ReserveConfigurationMap memory);\n\n /**\n * @notice Returns the configuration of the user across all the reserves\n * @param user The user address\n * @return The configuration of the user\n */\n function getUserConfiguration(address user)\n external\n view\n returns (DataTypes.UserConfigurationMap memory);\n\n /**\n * @notice Returns the normalized income of the reserve\n * @param asset The address of the underlying asset of the reserve\n * @return The reserve's normalized income\n */\n function getReserveNormalizedIncome(address asset)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the normalized variable debt per unit of asset\n * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a\n * \"dynamic\" variable index based on time, current stored index and virtual rate at the current\n * moment (approx. a borrower would get if opening a position). This means that is always used in\n * combination with variable debt supply/balances.\n * If using this function externally, consider that is possible to have an increasing normalized\n * variable debt that is not equivalent to how the variable debt index would be updated in storage\n * (e.g. only updates with non-zero variable debt supply)\n * @param asset The address of the underlying asset of the reserve\n * @return The reserve normalized variable debt\n */\n function getReserveNormalizedVariableDebt(address asset)\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the state and configuration of the reserve\n * @param asset The address of the underlying asset of the reserve\n * @return The state and configuration data of the reserve\n */\n function getReserveData(address asset)\n external\n view\n returns (DataTypes.ReserveData memory);\n\n /**\n * @notice Validates and finalizes an aToken transfer\n * @dev Only callable by the overlying aToken of the `asset`\n * @param asset The address of the underlying asset of the aToken\n * @param from The user from which the aTokens are transferred\n * @param to The user receiving the aTokens\n * @param amount The amount being transferred/withdrawn\n * @param balanceFromBefore The aToken balance of the `from` user before the transfer\n * @param balanceToBefore The aToken balance of the `to` user before the transfer\n */\n function finalizeTransfer(\n address asset,\n address from,\n address to,\n uint256 amount,\n uint256 balanceFromBefore,\n uint256 balanceToBefore\n ) external;\n\n /**\n * @notice Returns the list of the underlying assets of all the initialized reserves\n * @dev It does not include dropped reserves\n * @return The addresses of the underlying assets of the initialized reserves\n */\n function getReservesList() external view returns (address[] memory);\n\n /**\n * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct\n * @param id The id of the reserve as stored in the DataTypes.ReserveData struct\n * @return The address of the reserve associated with id\n */\n function getReserveAddressById(uint16 id) external view returns (address);\n\n /**\n * @notice Returns the PoolAddressesProvider connected to this contract\n * @return The address of the PoolAddressesProvider\n */\n function ADDRESSES_PROVIDER()\n external\n view\n returns (IPoolAddressesProvider);\n\n /**\n * @notice Updates the protocol fee on the bridging\n * @param bridgeProtocolFee The part of the premium sent to the protocol treasury\n */\n function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external;\n\n /**\n * @notice Updates flash loan premiums. Flash loan premium consists of two parts:\n * - A part is sent to aToken holders as extra, one time accumulated interest\n * - A part is collected by the protocol treasury\n * @dev The total premium is calculated on the total borrowed amount\n * @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal`\n * @dev Only callable by the PoolConfigurator contract\n * @param flashLoanPremiumTotal The total premium, expressed in bps\n * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps\n */\n function updateFlashloanPremiums(\n uint128 flashLoanPremiumTotal,\n uint128 flashLoanPremiumToProtocol\n ) external;\n\n /**\n * @notice Configures a new category for the eMode.\n * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.\n * The category 0 is reserved as it's the default for volatile assets\n * @param id The id of the category\n * @param config The configuration of the category\n */\n function configureEModeCategory(\n uint8 id,\n DataTypes.EModeCategory memory config\n ) external;\n\n /**\n * @notice Returns the data of an eMode category\n * @param id The id of the category\n * @return The configuration data of the category\n */\n function getEModeCategoryData(uint8 id)\n external\n view\n returns (DataTypes.EModeCategory memory);\n\n /**\n * @notice Allows a user to use the protocol in eMode\n * @param categoryId The id of the category\n */\n function setUserEMode(uint8 categoryId) external;\n\n /**\n * @notice Returns the eMode the user is using\n * @param user The address of the user\n * @return The eMode id\n */\n function getUserEMode(address user) external view returns (uint256);\n\n /**\n * @notice Resets the isolation mode total debt of the given asset to zero\n * @dev It requires the given asset has zero debt ceiling\n * @param asset The address of the underlying asset to reset the isolationModeTotalDebt\n */\n function resetIsolationModeTotalDebt(address asset) external;\n\n /**\n * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate\n * @return The percentage of available liquidity to borrow, expressed in bps\n */\n function MAX_STABLE_RATE_BORROW_SIZE_PERCENT()\n external\n view\n returns (uint256);\n\n /**\n * @notice Returns the total fee on flash loans\n * @return The total fee on flashloans\n */\n function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);\n\n /**\n * @notice Returns the part of the bridge fees sent to protocol\n * @return The bridge fee sent to the protocol treasury\n */\n function BRIDGE_PROTOCOL_FEE() external view returns (uint256);\n\n /**\n * @notice Returns the part of the flashloan fees sent to protocol\n * @return The flashloan fee sent to the protocol treasury\n */\n function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);\n\n /**\n * @notice Returns the maximum number of reserves supported to be listed in this Pool\n * @return The maximum number of reserves supported\n */\n function MAX_NUMBER_RESERVES() external view returns (uint16);\n\n /**\n * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens\n * @param assets The list of reserves for which the minting needs to be executed\n */\n function mintToTreasury(address[] calldata assets) external;\n\n /**\n * @notice Rescue and transfer tokens locked in this contract\n * @param token The address of the token\n * @param to The address of the recipient\n * @param amount The amount of token to transfer\n */\n function rescueTokens(address token, address to, uint256 amount) external;\n\n /**\n * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n * - E.g. User supplies 100 USDC and gets in return 100 aUSDC\n * @dev Deprecated: Use the `supply` function instead\n * @param asset The address of the underlying asset to supply\n * @param amount The amount to be supplied\n * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n * is a different wallet\n * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n * 0 if the action is executed directly by the user, without any middle-man\n */\n function deposit(\n address asset,\n uint256 amount,\n address onBehalfOf,\n uint16 referralCode\n ) external;\n}\n" + }, + "contracts/interfaces/aave/IPoolAddressesProvider.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.0;\n\n/**\n * @title IPoolAddressesProvider\n * @author Aave\n * @notice Defines the basic interface for a Pool Addresses Provider.\n */\ninterface IPoolAddressesProvider {\n /**\n * @dev Emitted when the market identifier is updated.\n * @param oldMarketId The old id of the market\n * @param newMarketId The new id of the market\n */\n event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);\n\n /**\n * @dev Emitted when the pool is updated.\n * @param oldAddress The old address of the Pool\n * @param newAddress The new address of the Pool\n */\n event PoolUpdated(address indexed oldAddress, address indexed newAddress);\n\n /**\n * @dev Emitted when the pool configurator is updated.\n * @param oldAddress The old address of the PoolConfigurator\n * @param newAddress The new address of the PoolConfigurator\n */\n event PoolConfiguratorUpdated(\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when the price oracle is updated.\n * @param oldAddress The old address of the PriceOracle\n * @param newAddress The new address of the PriceOracle\n */\n event PriceOracleUpdated(\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when the ACL manager is updated.\n * @param oldAddress The old address of the ACLManager\n * @param newAddress The new address of the ACLManager\n */\n event ACLManagerUpdated(\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when the ACL admin is updated.\n * @param oldAddress The old address of the ACLAdmin\n * @param newAddress The new address of the ACLAdmin\n */\n event ACLAdminUpdated(\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when the price oracle sentinel is updated.\n * @param oldAddress The old address of the PriceOracleSentinel\n * @param newAddress The new address of the PriceOracleSentinel\n */\n event PriceOracleSentinelUpdated(\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when the pool data provider is updated.\n * @param oldAddress The old address of the PoolDataProvider\n * @param newAddress The new address of the PoolDataProvider\n */\n event PoolDataProviderUpdated(\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when a new proxy is created.\n * @param id The identifier of the proxy\n * @param proxyAddress The address of the created proxy contract\n * @param implementationAddress The address of the implementation contract\n */\n event ProxyCreated(\n bytes32 indexed id,\n address indexed proxyAddress,\n address indexed implementationAddress\n );\n\n /**\n * @dev Emitted when a new non-proxied contract address is registered.\n * @param id The identifier of the contract\n * @param oldAddress The address of the old contract\n * @param newAddress The address of the new contract\n */\n event AddressSet(\n bytes32 indexed id,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n /**\n * @dev Emitted when the implementation of the proxy registered with id is updated\n * @param id The identifier of the contract\n * @param proxyAddress The address of the proxy contract\n * @param oldImplementationAddress The address of the old implementation contract\n * @param newImplementationAddress The address of the new implementation contract\n */\n event AddressSetAsProxy(\n bytes32 indexed id,\n address indexed proxyAddress,\n address oldImplementationAddress,\n address indexed newImplementationAddress\n );\n\n /**\n * @notice Returns the id of the Aave market to which this contract points to.\n * @return The market id\n */\n function getMarketId() external view returns (string memory);\n\n /**\n * @notice Associates an id with a specific PoolAddressesProvider.\n * @dev This can be used to create an onchain registry of PoolAddressesProviders to\n * identify and validate multiple Aave markets.\n * @param newMarketId The market id\n */\n function setMarketId(string calldata newMarketId) external;\n\n /**\n * @notice Returns an address by its identifier.\n * @dev The returned address might be an EOA or a contract, potentially proxied\n * @dev It returns ZERO if there is no registered address with the given id\n * @param id The id\n * @return The address of the registered for the specified id\n */\n function getAddress(bytes32 id) external view returns (address);\n\n /**\n * @notice General function to update the implementation of a proxy registered with\n * certain `id`. If there is no proxy registered, it will instantiate one and\n * set as implementation the `newImplementationAddress`.\n * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit\n * setter function, in order to avoid unexpected consequences\n * @param id The id\n * @param newImplementationAddress The address of the new implementation\n */\n function setAddressAsProxy(bytes32 id, address newImplementationAddress)\n external;\n\n /**\n * @notice Sets an address for an id replacing the address saved in the addresses map.\n * @dev IMPORTANT Use this function carefully, as it will do a hard replacement\n * @param id The id\n * @param newAddress The address to set\n */\n function setAddress(bytes32 id, address newAddress) external;\n\n /**\n * @notice Returns the address of the Pool proxy.\n * @return The Pool proxy address\n */\n function getPool() external view returns (address);\n\n /**\n * @notice Updates the implementation of the Pool, or creates a proxy\n * setting the new `pool` implementation when the function is called for the first time.\n * @param newPoolImpl The new Pool implementation\n */\n function setPoolImpl(address newPoolImpl) external;\n\n /**\n * @notice Returns the address of the PoolConfigurator proxy.\n * @return The PoolConfigurator proxy address\n */\n function getPoolConfigurator() external view returns (address);\n\n /**\n * @notice Updates the implementation of the PoolConfigurator, or creates a proxy\n * setting the new `PoolConfigurator` implementation when the function is called for the first time.\n * @param newPoolConfiguratorImpl The new PoolConfigurator implementation\n */\n function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;\n\n /**\n * @notice Returns the address of the price oracle.\n * @return The address of the PriceOracle\n */\n function getPriceOracle() external view returns (address);\n\n /**\n * @notice Updates the address of the price oracle.\n * @param newPriceOracle The address of the new PriceOracle\n */\n function setPriceOracle(address newPriceOracle) external;\n\n /**\n * @notice Returns the address of the ACL manager.\n * @return The address of the ACLManager\n */\n function getACLManager() external view returns (address);\n\n /**\n * @notice Updates the address of the ACL manager.\n * @param newAclManager The address of the new ACLManager\n */\n function setACLManager(address newAclManager) external;\n\n /**\n * @notice Returns the address of the ACL admin.\n * @return The address of the ACL admin\n */\n function getACLAdmin() external view returns (address);\n\n /**\n * @notice Updates the address of the ACL admin.\n * @param newAclAdmin The address of the new ACL admin\n */\n function setACLAdmin(address newAclAdmin) external;\n\n /**\n * @notice Returns the address of the price oracle sentinel.\n * @return The address of the PriceOracleSentinel\n */\n function getPriceOracleSentinel() external view returns (address);\n\n /**\n * @notice Updates the address of the price oracle sentinel.\n * @param newPriceOracleSentinel The address of the new PriceOracleSentinel\n */\n function setPriceOracleSentinel(address newPriceOracleSentinel) external;\n\n /**\n * @notice Returns the address of the data provider.\n * @return The address of the DataProvider\n */\n function getPoolDataProvider() external view returns (address);\n\n /**\n * @notice Updates the address of the data provider.\n * @param newDataProvider The address of the new DataProvider\n */\n function setPoolDataProvider(address newDataProvider) external;\n}\n" + }, + "contracts/interfaces/escrow/ICollateralEscrowV1.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport { Collateral, CollateralType } from \"../../bundle/interfaces/ICollateralBundle.sol\";\n\n// use the ones in ICollateralBundle instead !\n/*\nenum CollateralType {\n ERC20,\n ERC721,\n ERC1155\n}\n\nstruct Collateral {\n CollateralType _collateralType;\n uint256 _amount;\n uint256 _tokenId;\n address _collateralAddress;\n}\n*/\n\ninterface ICollateralEscrowV1 {\n /**\n * @notice Deposits a collateral asset into the escrow.\n * @param _collateralType The type of collateral asset to deposit (ERC721, ERC1155).\n * @param _collateralAddress The address of the collateral token.\n * @param _amount The amount to deposit.\n */\n function depositAsset(\n CollateralType _collateralType,\n address _collateralAddress,\n uint256 _amount,\n uint256 _tokenId\n ) external payable;\n\n /**\n * @notice Withdraws a collateral asset from the escrow.\n * @param _collateralAddress The address of the collateral contract.\n * @param _amount The amount to withdraw.\n * @param _recipient The address to send the assets to.\n */\n function withdraw(\n address _collateralAddress,\n uint256 _amount,\n address _recipient\n ) external;\n\n function getBid() external view returns (uint256);\n\n function initialize(uint256 _bidId) external;\n}\n" + }, + "contracts/interfaces/IASRegistry.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"./IASResolver.sol\";\n\n/**\n * @title The global AS registry interface.\n */\ninterface IASRegistry {\n /**\n * @title A struct representing a record for a submitted AS (Attestation Schema).\n */\n struct ASRecord {\n // A unique identifier of the AS.\n bytes32 uuid;\n // Optional schema resolver.\n IASResolver resolver;\n // Auto-incrementing index for reference, assigned by the registry itself.\n uint256 index;\n // Custom specification of the AS (e.g., an ABI).\n bytes schema;\n }\n\n /**\n * @dev Triggered when a new AS has been registered\n *\n * @param uuid The AS UUID.\n * @param index The AS index.\n * @param schema The AS schema.\n * @param resolver An optional AS schema resolver.\n * @param attester The address of the account used to register the AS.\n */\n event Registered(\n bytes32 indexed uuid,\n uint256 indexed index,\n bytes schema,\n IASResolver resolver,\n address attester\n );\n\n /**\n * @dev Submits and reserve a new AS\n *\n * @param schema The AS data schema.\n * @param resolver An optional AS schema resolver.\n *\n * @return The UUID of the new AS.\n */\n function register(bytes calldata schema, IASResolver resolver)\n external\n returns (bytes32);\n\n /**\n * @dev Returns an existing AS by UUID\n *\n * @param uuid The UUID of the AS to retrieve.\n *\n * @return The AS data members.\n */\n function getAS(bytes32 uuid) external view returns (ASRecord memory);\n\n /**\n * @dev Returns the global counter for the total number of attestations\n *\n * @return The global counter for the total number of attestations.\n */\n function getASCount() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IASResolver.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n\n// SPDX-License-Identifier: MIT\n\n/**\n * @title The interface of an optional AS resolver.\n */\ninterface IASResolver {\n /**\n * @dev Returns whether the resolver supports ETH transfers\n */\n function isPayable() external pure returns (bool);\n\n /**\n * @dev Resolves an attestation and verifier whether its data conforms to the spec.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The AS data schema.\n * @param data The actual attestation data.\n * @param expirationTime The expiration time of the attestation.\n * @param msgSender The sender of the original attestation message.\n *\n * @return Whether the data is valid according to the scheme.\n */\n function resolve(\n address recipient,\n bytes calldata schema,\n bytes calldata data,\n uint256 expirationTime,\n address msgSender\n ) external payable returns (bool);\n}\n" + }, + "contracts/interfaces/ICollateralManager.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport { Collateral } from \"../bundle/interfaces/ICollateralBundle.sol\";\n\ninterface ICollateralManager {\n /**\n * @notice Checks the validity of a borrower's collateral balance.\n * @param _bidId The id of the associated bid.\n * @param _collateralInfo Additional information about the collateral asset.\n * @return validation_ Boolean indicating if the collateral balance was validated.\n */\n function commitCollateral(\n uint256 _bidId,\n Collateral[] calldata _collateralInfo\n ) external returns (bool validation_);\n\n /**\n * @notice Gets the collateral info for a given bid id.\n * @param _bidId The bidId to return the collateral info for.\n * @return The stored collateral info.\n */\n function getCollateralInfo(uint256 _bidId)\n external\n view\n returns (Collateral[] memory);\n\n function getCollateralAmount(uint256 _bidId, address collateralAssetAddress)\n external\n view\n returns (uint256 _amount);\n\n /**\n * @notice Withdraws deposited collateral from the created escrow of a bid.\n * @param _bidId The id of the bid to withdraw collateral for.\n */\n function withdraw(uint256 _bidId) external;\n\n /**\n * @notice Sends the deposited collateral to a lender of a bid.\n * @notice Can only be called by the protocol.\n * @param _bidId The id of the liquidated bid.\n */\n function lenderClaimCollateral(uint256 _bidId) external;\n\n /**\n * @notice Sends the deposited collateral to a liquidator of a bid.\n * @notice Can only be called by the protocol.\n * @param _bidId The id of the liquidated bid.\n * @param _liquidatorAddress The address of the liquidator to send the collateral to.\n */\n function liquidateCollateral(uint256 _bidId, address _liquidatorAddress)\n external;\n}\n" + }, + "contracts/interfaces/ICollateralManagerV1.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\n//import { Collateral } from \"./escrow/ICollateralEscrowV1.sol\";\n\nimport { Collateral } from \"../bundle/interfaces/ICollateralBundle.sol\";\n\nimport \"./ICollateralManager.sol\";\n\ninterface ICollateralManagerV1 is ICollateralManager {\n function checkBalances(\n address _borrowerAddress,\n Collateral[] calldata _collateralInfo\n ) external returns (bool validated_, bool[] memory checks_);\n\n /**\n * @notice Deploys a new collateral escrow.\n * @param _bidId The associated bidId of the collateral escrow.\n */\n function deployAndDeposit(uint256 _bidId) external;\n\n /**\n * @notice Gets the address of a deployed escrow.\n * @notice _bidId The bidId to return the escrow for.\n * @return The address of the escrow.\n */\n function getEscrow(uint256 _bidId) external view returns (address);\n\n /**\n * @notice Re-checks the validity of a borrower's collateral balance committed to a bid.\n * @param _bidId The id of the associated bid.\n * @return validation_ Boolean indicating if the collateral balance was validated.\n */\n function revalidateCollateral(uint256 _bidId) external returns (bool);\n}\n" + }, + "contracts/interfaces/ICollateralManagerV2.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"./ICollateralManager.sol\";\n\n//use TokenBundle\n/*\nenum CollateralType {\n ERC20,\n ERC721,\n ERC1155\n}\n\nstruct Collateral {\n CollateralType _collateralType;\n uint256 _amount;\n uint256 _tokenId;\n address _collateralAddress;\n}*/\n\nimport { Collateral } from \"../bundle/interfaces/ICollateralBundle.sol\";\n\ninterface ICollateralManagerV2 is ICollateralManager {\n /**\n * @notice Deploys a new collateral escrow.\n * @param _bidId The associated bidId of the collateral escrow.\n */\n function depositCollateral(uint256 _bidId) external;\n\n /**\n * @notice Gets the address of a deployed escrow.\n * @notice _bidId The bidId to return the escrow for.\n * @return The address of the escrow.\n */\n // function getEscrow(uint256 _bidId) external view returns (address);\n\n /**\n * @notice Gets the collateral info for a given bid id.\n * @param _bidId The bidId to return the collateral info for.\n * @return The stored collateral info.\n */\n function getCollateralInfo(uint256 _bidId)\n external\n view\n returns (Collateral[] memory);\n\n function getCollateralAmount(uint256 _bidId, address collateralAssetAddress)\n external\n view\n returns (uint256 _amount);\n}\n" + }, + "contracts/interfaces/ICommitmentRolloverLoan.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\ninterface ICommitmentRolloverLoan {\n struct AcceptCommitmentArgs {\n uint256 commitmentId;\n uint256 principalAmount;\n uint256 collateralAmount;\n uint256 collateralTokenId;\n address collateralTokenAddress;\n uint16 interestRate;\n uint32 loanDuration;\n }\n}\n" + }, + "contracts/interfaces/IEAS.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"./IASRegistry.sol\";\nimport \"./IEASEIP712Verifier.sol\";\n\n/**\n * @title EAS - Ethereum Attestation Service interface\n */\ninterface IEAS {\n /**\n * @dev A struct representing a single attestation.\n */\n struct Attestation {\n // A unique identifier of the attestation.\n bytes32 uuid;\n // A unique identifier of the AS.\n bytes32 schema;\n // The recipient of the attestation.\n address recipient;\n // The attester/sender of the attestation.\n address attester;\n // The time when the attestation was created (Unix timestamp).\n uint256 time;\n // The time when the attestation expires (Unix timestamp).\n uint256 expirationTime;\n // The time when the attestation was revoked (Unix timestamp).\n uint256 revocationTime;\n // The UUID of the related attestation.\n bytes32 refUUID;\n // Custom attestation data.\n bytes data;\n }\n\n /**\n * @dev Triggered when an attestation has been made.\n *\n * @param recipient The recipient of the attestation.\n * @param attester The attesting account.\n * @param uuid The UUID the revoked attestation.\n * @param schema The UUID of the AS.\n */\n event Attested(\n address indexed recipient,\n address indexed attester,\n bytes32 uuid,\n bytes32 indexed schema\n );\n\n /**\n * @dev Triggered when an attestation has been revoked.\n *\n * @param recipient The recipient of the attestation.\n * @param attester The attesting account.\n * @param schema The UUID of the AS.\n * @param uuid The UUID the revoked attestation.\n */\n event Revoked(\n address indexed recipient,\n address indexed attester,\n bytes32 uuid,\n bytes32 indexed schema\n );\n\n /**\n * @dev Returns the address of the AS global registry.\n *\n * @return The address of the AS global registry.\n */\n function getASRegistry() external view returns (IASRegistry);\n\n /**\n * @dev Returns the address of the EIP712 verifier used to verify signed attestations.\n *\n * @return The address of the EIP712 verifier used to verify signed attestations.\n */\n function getEIP712Verifier() external view returns (IEASEIP712Verifier);\n\n /**\n * @dev Returns the global counter for the total number of attestations.\n *\n * @return The global counter for the total number of attestations.\n */\n function getAttestationsCount() external view returns (uint256);\n\n /**\n * @dev Attests to a specific AS.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n * @param expirationTime The expiration time of the attestation.\n * @param refUUID An optional related attestation's UUID.\n * @param data Additional custom data.\n *\n * @return The UUID of the new attestation.\n */\n function attest(\n address recipient,\n bytes32 schema,\n uint256 expirationTime,\n bytes32 refUUID,\n bytes calldata data\n ) external payable returns (bytes32);\n\n /**\n * @dev Attests to a specific AS using a provided EIP712 signature.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n * @param expirationTime The expiration time of the attestation.\n * @param refUUID An optional related attestation's UUID.\n * @param data Additional custom data.\n * @param attester The attesting account.\n * @param v The recovery ID.\n * @param r The x-coordinate of the nonce R.\n * @param s The signature data.\n *\n * @return The UUID of the new attestation.\n */\n function attestByDelegation(\n address recipient,\n bytes32 schema,\n uint256 expirationTime,\n bytes32 refUUID,\n bytes calldata data,\n address attester,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external payable returns (bytes32);\n\n /**\n * @dev Revokes an existing attestation to a specific AS.\n *\n * @param uuid The UUID of the attestation to revoke.\n */\n function revoke(bytes32 uuid) external;\n\n /**\n * @dev Attests to a specific AS using a provided EIP712 signature.\n *\n * @param uuid The UUID of the attestation to revoke.\n * @param attester The attesting account.\n * @param v The recovery ID.\n * @param r The x-coordinate of the nonce R.\n * @param s The signature data.\n */\n function revokeByDelegation(\n bytes32 uuid,\n address attester,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns an existing attestation by UUID.\n *\n * @param uuid The UUID of the attestation to retrieve.\n *\n * @return The attestation data members.\n */\n function getAttestation(bytes32 uuid)\n external\n view\n returns (Attestation memory);\n\n /**\n * @dev Checks whether an attestation exists.\n *\n * @param uuid The UUID of the attestation to retrieve.\n *\n * @return Whether an attestation exists.\n */\n function isAttestationValid(bytes32 uuid) external view returns (bool);\n\n /**\n * @dev Checks whether an attestation is active.\n *\n * @param uuid The UUID of the attestation to retrieve.\n *\n * @return Whether an attestation is active.\n */\n function isAttestationActive(bytes32 uuid) external view returns (bool);\n\n /**\n * @dev Returns all received attestation UUIDs.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n * @param start The offset to start from.\n * @param length The number of total members to retrieve.\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\n *\n * @return An array of attestation UUIDs.\n */\n function getReceivedAttestationUUIDs(\n address recipient,\n bytes32 schema,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view returns (bytes32[] memory);\n\n /**\n * @dev Returns the number of received attestation UUIDs.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n *\n * @return The number of attestations.\n */\n function getReceivedAttestationUUIDsCount(address recipient, bytes32 schema)\n external\n view\n returns (uint256);\n\n /**\n * @dev Returns all sent attestation UUIDs.\n *\n * @param attester The attesting account.\n * @param schema The UUID of the AS.\n * @param start The offset to start from.\n * @param length The number of total members to retrieve.\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\n *\n * @return An array of attestation UUIDs.\n */\n function getSentAttestationUUIDs(\n address attester,\n bytes32 schema,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view returns (bytes32[] memory);\n\n /**\n * @dev Returns the number of sent attestation UUIDs.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n *\n * @return The number of attestations.\n */\n function getSentAttestationUUIDsCount(address recipient, bytes32 schema)\n external\n view\n returns (uint256);\n\n /**\n * @dev Returns all attestations related to a specific attestation.\n *\n * @param uuid The UUID of the attestation to retrieve.\n * @param start The offset to start from.\n * @param length The number of total members to retrieve.\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\n *\n * @return An array of attestation UUIDs.\n */\n function getRelatedAttestationUUIDs(\n bytes32 uuid,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view returns (bytes32[] memory);\n\n /**\n * @dev Returns the number of related attestation UUIDs.\n *\n * @param uuid The UUID of the attestation to retrieve.\n *\n * @return The number of related attestations.\n */\n function getRelatedAttestationUUIDsCount(bytes32 uuid)\n external\n view\n returns (uint256);\n\n /**\n * @dev Returns all per-schema attestation UUIDs.\n *\n * @param schema The UUID of the AS.\n * @param start The offset to start from.\n * @param length The number of total members to retrieve.\n * @param reverseOrder Whether the offset starts from the end and the data is returned in reverse.\n *\n * @return An array of attestation UUIDs.\n */\n function getSchemaAttestationUUIDs(\n bytes32 schema,\n uint256 start,\n uint256 length,\n bool reverseOrder\n ) external view returns (bytes32[] memory);\n\n /**\n * @dev Returns the number of per-schema attestation UUIDs.\n *\n * @param schema The UUID of the AS.\n *\n * @return The number of attestations.\n */\n function getSchemaAttestationUUIDsCount(bytes32 schema)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/interfaces/IEASEIP712Verifier.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n\n// SPDX-License-Identifier: MIT\n\n/**\n * @title EIP712 typed signatures verifier for EAS delegated attestations interface.\n */\ninterface IEASEIP712Verifier {\n /**\n * @dev Returns the current nonce per-account.\n *\n * @param account The requested accunt.\n *\n * @return The current nonce.\n */\n function getNonce(address account) external view returns (uint256);\n\n /**\n * @dev Verifies signed attestation.\n *\n * @param recipient The recipient of the attestation.\n * @param schema The UUID of the AS.\n * @param expirationTime The expiration time of the attestation.\n * @param refUUID An optional related attestation's UUID.\n * @param data Additional custom data.\n * @param attester The attesting account.\n * @param v The recovery ID.\n * @param r The x-coordinate of the nonce R.\n * @param s The signature data.\n */\n function attest(\n address recipient,\n bytes32 schema,\n uint256 expirationTime,\n bytes32 refUUID,\n bytes calldata data,\n address attester,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Verifies signed revocations.\n *\n * @param uuid The UUID of the attestation to revoke.\n * @param attester The attesting account.\n * @param v The recovery ID.\n * @param r The x-coordinate of the nonce R.\n * @param s The signature data.\n */\n function revoke(\n bytes32 uuid,\n address attester,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n" + }, + "contracts/interfaces/IEscrowVault.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\ninterface IEscrowVault {\n /**\n * @notice Deposit tokens on behalf of another account\n * @param account The address of the account\n * @param token The address of the token\n * @param amount The amount to increase the balance\n */\n function deposit(address account, address token, uint256 amount) external;\n}\n" + }, + "contracts/interfaces/IExtensionsContext.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IExtensionsContext {\n function hasExtension(address extension, address account)\n external\n view\n returns (bool);\n\n function addExtension(address extension) external;\n\n function revokeExtension(address extension) external;\n}\n" + }, + "contracts/interfaces/IFlashRolloverLoan.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IFlashRolloverLoan {\n struct RolloverCallbackArgs {\n uint256 loanId;\n address borrower;\n uint256 borrowerAmount;\n bytes acceptCommitmentArgs;\n }\n}\n" + }, + "contracts/interfaces/ILenderCommitmentForwarder.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\ninterface ILenderCommitmentForwarder {\n enum CommitmentCollateralType {\n NONE, // no collateral required\n ERC20,\n ERC721,\n ERC1155,\n ERC721_ANY_ID,\n ERC1155_ANY_ID,\n ERC721_MERKLE_PROOF,\n ERC1155_MERKLE_PROOF\n }\n\n /**\n * @notice Details about a lender's capital commitment.\n * @param maxPrincipal Amount of tokens being committed by the lender. Max amount that can be loaned.\n * @param expiration Expiration time in seconds, when the commitment expires.\n * @param maxDuration Length of time, in seconds that the lender's capital can be lent out for.\n * @param minInterestRate Minimum Annual percentage to be applied for loans using the lender's capital.\n * @param collateralTokenAddress The address for the token contract that must be used to provide collateral for loans for this commitment.\n * @param maxPrincipalPerCollateralAmount The amount of principal that can be used for a loan per each unit of collateral, expanded additionally by principal decimals.\n * @param collateralTokenType The type of asset of the collateralTokenAddress (ERC20, ERC721, or ERC1155).\n * @param lender The address of the lender for this commitment.\n * @param marketId The market id for this commitment.\n * @param principalTokenAddress The address for the token contract that will be used to provide principal for loans of this commitment.\n */\n struct Commitment {\n uint256 maxPrincipal;\n uint32 expiration;\n uint32 maxDuration;\n uint16 minInterestRate;\n address collateralTokenAddress;\n uint256 collateralTokenId; //we use this for the MerkleRootHash for type ERC721_MERKLE_PROOF\n uint256 maxPrincipalPerCollateralAmount;\n CommitmentCollateralType collateralTokenType;\n address lender;\n uint256 marketId;\n address principalTokenAddress;\n }\n\n // mapping(uint256 => Commitment) public commitments;\n\n function getCommitmentMarketId(uint256 _commitmentId)\n external\n view\n returns (uint256);\n\n function getCommitmentLender(uint256 _commitmentId)\n external\n view\n returns (address);\n\n function getCommitmentAcceptedPrincipal(uint256 _commitmentId)\n external\n view\n returns (uint256);\n\n function getCommitmentMaxPrincipal(uint256 _commitmentId)\n external\n view\n returns (uint256);\n\n function createCommitment(\n Commitment calldata _commitment,\n address[] calldata _borrowerAddressList\n ) external returns (uint256);\n\n function acceptCommitmentWithRecipient(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration\n ) external returns (uint256 bidId_);\n\n function acceptCommitmentWithRecipientAndProof(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration,\n bytes32[] calldata _merkleProof\n ) external returns (uint256 bidId_);\n}\n" + }, + "contracts/interfaces/ILenderManager.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n\n// SPDX-License-Identifier: MIT\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\";\n\nabstract contract ILenderManager is IERC721Upgradeable {\n /**\n * @notice Registers a new active lender for a loan, minting the nft.\n * @param _bidId The id for the loan to set.\n * @param _newLender The address of the new active lender.\n */\n function registerLoan(uint256 _bidId, address _newLender) external virtual;\n}\n" + }, + "contracts/interfaces/IMarketLiquidityRewards.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IMarketLiquidityRewards {\n struct RewardAllocation {\n address allocator;\n address rewardTokenAddress;\n uint256 rewardTokenAmount;\n uint256 marketId;\n //requirements for loan\n address requiredPrincipalTokenAddress; //0 for any\n address requiredCollateralTokenAddress; //0 for any -- could be an enumerable set?\n uint256 minimumCollateralPerPrincipalAmount;\n uint256 rewardPerLoanPrincipalAmount;\n uint32 bidStartTimeMin;\n uint32 bidStartTimeMax;\n AllocationStrategy allocationStrategy;\n }\n\n enum AllocationStrategy {\n BORROWER,\n LENDER\n }\n\n function allocateRewards(RewardAllocation calldata _allocation)\n external\n returns (uint256 allocationId_);\n\n function increaseAllocationAmount(\n uint256 _allocationId,\n uint256 _tokenAmount\n ) external;\n\n function deallocateRewards(uint256 _allocationId, uint256 _amount) external;\n\n function claimRewards(uint256 _allocationId, uint256 _bidId) external;\n\n function rewardClaimedForBid(uint256 _bidId, uint256 _allocationId)\n external\n view\n returns (bool);\n\n function getRewardTokenAmount(uint256 _allocationId)\n external\n view\n returns (uint256);\n\n function initialize() external;\n}\n" + }, + "contracts/interfaces/IMarketRegistry_V1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../EAS/TellerAS.sol\";\nimport { PaymentType, PaymentCycleType } from \"../libraries/V2Calculations.sol\";\n\nimport { IMarketRegistry } from \"./IMarketRegistry.sol\";\n\ninterface IMarketRegistry_V1 is IMarketRegistry {\n function initialize(TellerAS tellerAs) external;\n \n\n\n function createMarket(\n address _initialOwner,\n uint32 _paymentCycleDuration,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n PaymentType _paymentType,\n PaymentCycleType _paymentCycleType,\n string calldata _uri\n ) external returns (uint256 marketId_);\n\n function createMarket(\n address _initialOwner,\n uint32 _paymentCycleDuration,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n string calldata _uri\n ) external returns (uint256 marketId_);\n\n function getPaymentCycle(uint256 _marketId)\n external\n view\n returns (uint32, PaymentCycleType);\n}\n" + }, + "contracts/interfaces/IMarketRegistry_V2.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport { PaymentType, PaymentCycleType } from \"../libraries/V2Calculations.sol\";\n\nimport { IMarketRegistry } from \"./IMarketRegistry.sol\";\n\ninterface IMarketRegistry_V2 is IMarketRegistry {\n struct MarketplaceTerms {\n uint16 marketplaceFeePercent; // 10000 is 100%\n PaymentType paymentType;\n PaymentCycleType paymentCycleType;\n uint32 paymentCycleDuration; // unix time (seconds)\n uint32 paymentDefaultDuration; //unix time\n uint32 bidExpirationTime; //unix time\n address feeRecipient;\n }\n\n \n function getMarketTermsForLending(bytes32 _marketTermsId)\n external\n view\n returns (uint32, PaymentCycleType, PaymentType, uint32, uint32);\n\n function getMarketFeeTerms(bytes32 _marketTermsId)\n external\n view\n returns (address, uint16);\n\n function getBidExpirationTimeForTerms(bytes32 _marketTermsId)\n external\n view\n returns (uint32);\n\n function getPaymentDefaultDurationForTerms(bytes32 _marketTermsId)\n external\n view\n returns (uint32);\n\n function getPaymentTypeForTerms(bytes32 _marketTermsId)\n external\n view\n returns (PaymentType);\n\n function getPaymentCycleTypeForTerms(bytes32 _marketTermsId)\n external\n view\n returns (PaymentCycleType);\n\n function getPaymentCycleDurationForTerms(bytes32 _marketTermsId)\n external\n view\n returns (uint32);\n\n function getPaymentCycleType(uint256 _marketId)\n external\n view\n returns (PaymentCycleType);\n\n function getPaymentCycleDuration(uint256 _marketId)\n external\n view\n returns (uint32);\n\n function createMarket(\n address _initialOwner,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n string calldata _uri,\n MarketplaceTerms memory _marketTermsParams\n ) external returns (uint256 marketId_, bytes32 marketTerms_);\n\n \n\n function getCurrentTermsForMarket(uint256 _marketId)\n external\n view\n returns (bytes32);\n}\n" + }, + "contracts/interfaces/IMarketRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { PaymentType, PaymentCycleType } from \"../libraries/V2Calculations.sol\";\n\n\ninterface IMarketRegistry {\n function isMarketOpen(uint256 _marketId) external view returns (bool);\n\n function isMarketClosed(uint256 _marketId) external view returns (bool);\n\n function getMarketOwner(uint256 _marketId) external view returns (address);\n\n function closeMarket(uint256 _marketId) external;\n\n function getMarketFeeRecipient(uint256 _marketId)\n external\n view\n returns (address);\n\n function getMarketURI(uint256 _marketId)\n external\n view\n returns (string memory);\n\n \n\n function getPaymentDefaultDuration(uint256 _marketId)\n external\n view\n returns (uint32);\n\n function getBidExpirationTime(uint256 _marketId)\n external\n view\n returns (uint32);\n\n function getPaymentType(uint256 _marketId)\n external\n view\n returns (PaymentType);\n\n\n function getMarketplaceFee(uint256 _marketId)\n external\n view\n returns (uint16);\n\n function isVerifiedBorrower(uint256 _marketId, address _borrower)\n external\n view\n returns (bool, bytes32);\n\n function isVerifiedLender(uint256 _marketId, address _lender)\n external\n view\n returns (bool, bytes32);\n\n\n}\n" + }, + "contracts/interfaces/IProtocolFee.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IProtocolFee {\n function protocolFee() external view returns (uint16);\n}\n" + }, + "contracts/interfaces/IReputationManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum RepMark {\n Good,\n Delinquent,\n Default\n}\n\ninterface IReputationManager {\n function initialize(address protocolAddress) external;\n\n function getDelinquentLoanIds(address _account)\n external\n returns (uint256[] memory);\n\n function getDefaultedLoanIds(address _account)\n external\n returns (uint256[] memory);\n\n function getCurrentDelinquentLoanIds(address _account)\n external\n returns (uint256[] memory);\n\n function getCurrentDefaultLoanIds(address _account)\n external\n returns (uint256[] memory);\n\n // function updateAccountReputation(address _account) external;\n\n function updateAccountReputation(address _account, uint256 _bidId)\n external\n returns (RepMark);\n}\n" + }, + "contracts/interfaces/ITellerV2.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Payment, BidState } from \"../TellerV2Storage.sol\";\n//import { Collateral } from \"./escrow/ICollateralEscrowV1.sol\";\n\nimport { Collateral } from \"../bundle/interfaces/ICollateralBundle.sol\";\nimport \"./ICollateralManager.sol\";\n\ninterface ITellerV2 {\n /**\n * @notice Function for a borrower to create a bid for a loan.\n * @param _lendingToken The lending token asset requested to be borrowed.\n * @param _marketplaceId The unique id of the marketplace for the bid.\n * @param _principal The principal amount of the loan bid.\n * @param _duration The recurrent length of time before which a payment is due.\n * @param _APR The proposed interest rate for the loan bid.\n * @param _metadataURI The URI for additional borrower loan information as part of loan bid.\n * @param _receiver The address where the loan amount will be sent to.\n */\n function submitBid(\n address _lendingToken,\n uint256 _marketplaceId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata _metadataURI,\n address _receiver\n ) external returns (uint256 bidId_);\n\n /**\n * @notice Function for a borrower to create a bid for a loan with Collateral.\n * @param _lendingToken The lending token asset requested to be borrowed.\n * @param _marketplaceId The unique id of the marketplace for the bid.\n * @param _principal The principal amount of the loan bid.\n * @param _duration The recurrent length of time before which a payment is due.\n * @param _APR The proposed interest rate for the loan bid.\n * @param _metadataURI The URI for additional borrower loan information as part of loan bid.\n * @param _receiver The address where the loan amount will be sent to.\n * @param _collateralInfo Additional information about the collateral asset.\n */\n function submitBid(\n address _lendingToken,\n uint256 _marketplaceId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata _metadataURI,\n address _receiver,\n Collateral[] calldata _collateralInfo\n ) external returns (uint256 bidId_);\n\n /**\n * @notice Function for a lender to accept a proposed loan bid.\n * @param _bidId The id of the loan bid to accept.\n */\n function lenderAcceptBid(uint256 _bidId)\n external\n returns (\n uint256 amountToProtocol,\n uint256 amountToMarketplace,\n uint256 amountToBorrower\n );\n\n /**\n * @notice Function for users to make the minimum amount due for an active loan.\n * @param _bidId The id of the loan to make the payment towards.\n */\n function repayLoanMinimum(uint256 _bidId) external;\n\n /**\n * @notice Function for users to repay an active loan in full.\n * @param _bidId The id of the loan to make the payment towards.\n */\n function repayLoanFull(uint256 _bidId) external;\n\n /**\n * @notice Function for users to make a payment towards an active loan.\n * @param _bidId The id of the loan to make the payment towards.\n * @param _amount The amount of the payment.\n */\n function repayLoan(uint256 _bidId, uint256 _amount) external;\n\n /**\n * @notice Checks to see if a borrower is delinquent.\n * @param _bidId The id of the loan bid to check for.\n */\n function isLoanDefaulted(uint256 _bidId) external view returns (bool);\n\n /**\n * @notice Checks to see if a loan was delinquent for longer than liquidation delay.\n * @param _bidId The id of the loan bid to check for.\n */\n function isLoanLiquidateable(uint256 _bidId) external view returns (bool);\n\n /**\n * @notice Checks to see if a borrower is delinquent.\n * @param _bidId The id of the loan bid to check for.\n */\n function isPaymentLate(uint256 _bidId) external view returns (bool);\n\n function getBidState(uint256 _bidId) external view returns (BidState);\n\n /* \n function getBorrowerActiveLoanIds(address _borrower)\n external\n view\n returns (uint256[] memory);\n */\n\n /**\n * @notice Returns the borrower address for a given bid.\n * @param _bidId The id of the bid/loan to get the borrower for.\n * @return borrower_ The address of the borrower associated with the bid.\n */\n function getLoanBorrower(uint256 _bidId)\n external\n view\n returns (address borrower_);\n\n /**\n * @notice Returns the lender address for a given bid.\n * @param _bidId The id of the bid/loan to get the lender for.\n * @return lender_ The address of the lender associated with the bid.\n */\n function getLoanLender(uint256 _bidId)\n external\n view\n returns (address lender_);\n\n function getLoanLendingToken(uint256 _bidId)\n external\n view\n returns (address token_);\n\n function getLoanMarketId(uint256 _bidId) external view returns (uint256);\n\n function getLoanSummary(uint256 _bidId)\n external\n view\n returns (\n address borrower,\n address lender,\n uint256 marketId,\n address principalTokenAddress,\n uint256 principalAmount,\n uint32 acceptedTimestamp,\n uint32 lastRepaidTimestamp,\n BidState bidState\n );\n\n function getCollateralManagerForBid(uint256 _bidId)\n external\n view\n returns (ICollateralManager);\n\n function calculateAmountOwed(uint256 _bidId, uint256 _timestamp)\n external\n view\n returns (Payment memory owed);\n\n function calculateAmountDue(uint256 _bidId, uint256 _timestamp)\n external\n view\n returns (Payment memory due);\n\n function collateralManager() external view returns (address);\n}\n" + }, + "contracts/interfaces/ITellerV2Autopay.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ITellerV2Autopay {\n function setAutoPayEnabled(uint256 _bidId, bool _autoPayEnabled) external;\n\n function autoPayLoanMinimum(uint256 _bidId) external;\n\n function initialize(uint16 _newFee, address _newOwner) external;\n\n function setAutopayFee(uint16 _newFee) external;\n}\n" + }, + "contracts/interfaces/ITellerV2MarketForwarder.sol": { + "content": "// SPDX-Licence-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\nimport { Collateral } from \"./escrow/ICollateralEscrowV1.sol\";\n\ninterface ITellerV2MarketForwarder {\n struct CreateLoanArgs {\n uint256 marketId;\n address lendingToken;\n uint256 principal;\n uint32 duration;\n uint16 interestRate;\n string metadataURI;\n address recipient;\n Collateral[] collateral;\n }\n}\n" + }, + "contracts/interfaces/ITellerV2Storage.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ITellerV2Storage {\n function marketRegistry() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWETH.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @notice It is the interface of functions that we use for the canonical WETH contract.\n *\n * @author develop@teller.finance\n */\ninterface IWETH {\n /**\n * @notice It withdraws ETH from the contract by sending it to the caller and reducing the caller's internal balance of WETH.\n * @param amount The amount of ETH to withdraw.\n */\n function withdraw(uint256 amount) external;\n\n /**\n * @notice It deposits ETH into the contract and increases the caller's internal balance of WETH.\n */\n function deposit() external payable;\n\n /**\n * @notice It gets the ETH deposit balance of an {account}.\n * @param account Address to get balance of.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @notice It transfers the WETH amount specified to the given {account}.\n * @param to Address to transfer to\n * @param value Amount of WETH to transfer\n */\n function transfer(address to, uint256 value) external returns (bool);\n}\n" + }, + "contracts/LenderCommitmentForwarder/extensions/CommitmentRolloverLoan.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Contracts\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\n// Interfaces\nimport \"../../interfaces/ITellerV2.sol\";\nimport \"../../interfaces/IProtocolFee.sol\";\nimport \"../../interfaces/ITellerV2Storage.sol\";\nimport \"../../interfaces/IMarketRegistry.sol\";\nimport \"../../interfaces/ILenderCommitmentForwarder.sol\";\nimport \"../../interfaces/ICommitmentRolloverLoan.sol\";\nimport \"../../libraries/NumbersLib.sol\";\n\ncontract CommitmentRolloverLoan is ICommitmentRolloverLoan {\n using AddressUpgradeable for address;\n using NumbersLib for uint256;\n\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n ITellerV2 public immutable TELLER_V2;\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n ILenderCommitmentForwarder public immutable LENDER_COMMITMENT_FORWARDER;\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address _tellerV2, address _lenderCommitmentForwarder) {\n TELLER_V2 = ITellerV2(_tellerV2);\n LENDER_COMMITMENT_FORWARDER = ILenderCommitmentForwarder(\n _lenderCommitmentForwarder\n );\n }\n\n /**\n * @notice Allows a borrower to rollover a loan to a new commitment.\n * @param _loanId The ID of the existing loan.\n * @param _rolloverAmount The amount to rollover.\n * @param _commitmentArgs Arguments for the commitment to accept.\n * @return newLoanId_ The ID of the new loan created by accepting the commitment.\n */\n function rolloverLoan(\n uint256 _loanId,\n uint256 _rolloverAmount,\n AcceptCommitmentArgs calldata _commitmentArgs\n ) external returns (uint256 newLoanId_) {\n address borrower = TELLER_V2.getLoanBorrower(_loanId);\n require(borrower == msg.sender, \"CommitmentRolloverLoan: not borrower\");\n\n // Get lending token and balance before\n IERC20Upgradeable lendingToken = IERC20Upgradeable(\n TELLER_V2.getLoanLendingToken(_loanId)\n );\n uint256 balanceBefore = lendingToken.balanceOf(address(this));\n\n if (_rolloverAmount > 0) {\n //accept funds from the borrower to this contract\n lendingToken.transferFrom(borrower, address(this), _rolloverAmount);\n }\n\n // Accept commitment and receive funds to this contract\n newLoanId_ = _acceptCommitment(_commitmentArgs);\n\n // Calculate funds received\n uint256 fundsReceived = lendingToken.balanceOf(address(this)) -\n balanceBefore;\n\n // Approve TellerV2 to spend funds and repay loan\n lendingToken.approve(address(TELLER_V2), fundsReceived);\n TELLER_V2.repayLoanFull(_loanId);\n\n uint256 fundsRemaining = lendingToken.balanceOf(address(this)) -\n balanceBefore;\n\n if (fundsRemaining > 0) {\n lendingToken.transfer(borrower, fundsRemaining);\n }\n }\n\n /**\n * @notice Calculates the amount for loan rollover, determining if the borrower owes or receives funds.\n * @param _loanId The ID of the loan to calculate the rollover amount for.\n * @param _commitmentArgs Arguments for the commitment.\n * @param _timestamp The timestamp for when the calculation is executed.\n * @return _amount The calculated amount, positive if borrower needs to send funds and negative if they will receive funds.\n */\n function calculateRolloverAmount(\n uint256 _loanId,\n AcceptCommitmentArgs calldata _commitmentArgs,\n uint256 _timestamp\n ) external view returns (int256 _amount) {\n Payment memory repayAmountOwed = TELLER_V2.calculateAmountOwed(\n _loanId,\n _timestamp\n );\n\n _amount +=\n int256(repayAmountOwed.principal) +\n int256(repayAmountOwed.interest);\n\n uint256 _marketId = _getMarketIdForCommitment(\n _commitmentArgs.commitmentId\n );\n uint16 marketFeePct = _getMarketFeePct(_marketId);\n uint16 protocolFeePct = _getProtocolFeePct();\n\n uint256 commitmentPrincipalRequested = _commitmentArgs.principalAmount;\n uint256 amountToMarketplace = commitmentPrincipalRequested.percent(\n marketFeePct\n );\n uint256 amountToProtocol = commitmentPrincipalRequested.percent(\n protocolFeePct\n );\n\n uint256 amountToBorrower = commitmentPrincipalRequested -\n amountToProtocol -\n amountToMarketplace;\n\n _amount -= int256(amountToBorrower);\n }\n\n /**\n * @notice Internally accepts a commitment via the `LENDER_COMMITMENT_FORWARDER`.\n * @param _commitmentArgs Arguments required to accept a commitment.\n * @return bidId_ The ID of the bid associated with the accepted commitment.\n */\n function _acceptCommitment(AcceptCommitmentArgs calldata _commitmentArgs)\n internal\n returns (uint256 bidId_)\n {\n bytes memory responseData = address(LENDER_COMMITMENT_FORWARDER)\n .functionCall(\n abi.encodePacked(\n abi.encodeWithSelector(\n ILenderCommitmentForwarder\n .acceptCommitmentWithRecipient\n .selector,\n _commitmentArgs.commitmentId,\n _commitmentArgs.principalAmount,\n _commitmentArgs.collateralAmount,\n _commitmentArgs.collateralTokenId,\n _commitmentArgs.collateralTokenAddress,\n address(this),\n _commitmentArgs.interestRate,\n _commitmentArgs.loanDuration\n ),\n msg.sender\n )\n );\n\n (bidId_) = abi.decode(responseData, (uint256));\n }\n\n /**\n * @notice Retrieves the market ID associated with a given commitment.\n * @param _commitmentId The ID of the commitment for which to fetch the market ID.\n * @return The ID of the market associated with the provided commitment.\n */\n function _getMarketIdForCommitment(uint256 _commitmentId)\n internal\n view\n returns (uint256)\n {\n return LENDER_COMMITMENT_FORWARDER.getCommitmentMarketId(_commitmentId);\n }\n\n /**\n * @notice Fetches the marketplace fee percentage for a given market ID.\n * @param _marketId The ID of the market for which to fetch the fee percentage.\n * @return The marketplace fee percentage for the provided market ID.\n */\n function _getMarketFeePct(uint256 _marketId)\n internal\n view\n returns (uint16)\n {\n address _marketRegistryAddress = ITellerV2Storage(address(TELLER_V2))\n .marketRegistry();\n\n return\n IMarketRegistry(_marketRegistryAddress).getMarketplaceFee(\n _marketId\n );\n }\n\n /**\n * @notice Fetches the protocol fee percentage from the Teller V2 protocol.\n * @return The protocol fee percentage as defined in the Teller V2 protocol.\n */\n function _getProtocolFeePct() internal view returns (uint16) {\n return IProtocolFee(address(TELLER_V2)).protocolFee();\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/extensions/ExtensionsContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../interfaces/IExtensionsContext.sol\";\nimport \"@openzeppelin/contracts-upgradeable/metatx/ERC2771ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol\";\n\nabstract contract ExtensionsContextUpgradeable is IExtensionsContext {\n using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private userExtensions;\n\n event ExtensionAdded(address extension, address sender);\n event ExtensionRevoked(address extension, address sender);\n\n function hasExtension(address account, address extension)\n public\n view\n returns (bool)\n {\n return userExtensions[account][extension];\n }\n\n function addExtension(address extension) external {\n require(\n _msgSender() != extension,\n \"ExtensionsContextUpgradeable: cannot approve own extension\"\n );\n\n userExtensions[_msgSender()][extension] = true;\n emit ExtensionAdded(extension, _msgSender());\n }\n\n function revokeExtension(address extension) external {\n userExtensions[_msgSender()][extension] = false;\n emit ExtensionRevoked(extension, _msgSender());\n }\n\n function _msgSender() internal view virtual returns (address sender) {\n address sender;\n\n if (msg.data.length >= 20) {\n assembly {\n sender := shr(96, calldataload(sub(calldatasize(), 20)))\n }\n\n if (hasExtension(sender, msg.sender)) {\n return sender;\n }\n }\n\n return msg.sender;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Contracts\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n// Interfaces\nimport \"../../interfaces/ITellerV2.sol\";\nimport \"../../interfaces/IProtocolFee.sol\";\nimport \"../../interfaces/ITellerV2Storage.sol\";\nimport \"../../interfaces/IMarketRegistry.sol\";\nimport \"../../interfaces/ILenderCommitmentForwarder.sol\";\nimport \"../../interfaces/IFlashRolloverLoan.sol\";\nimport \"../../libraries/NumbersLib.sol\";\n\nimport { IPool } from \"../../interfaces/aave/IPool.sol\";\nimport { IFlashLoanSimpleReceiver } from \"../../interfaces/aave/IFlashLoanSimpleReceiver.sol\";\nimport { IPoolAddressesProvider } from \"../../interfaces/aave/IPoolAddressesProvider.sol\";\n \n//https://docs.aave.com/developers/v/1.0/tutorials/performing-a-flash-loan/...-in-your-project\n\ncontract FlashRolloverLoan_G1 is IFlashLoanSimpleReceiver, IFlashRolloverLoan {\n using AddressUpgradeable for address;\n using NumbersLib for uint256;\n\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n ITellerV2 public immutable TELLER_V2;\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n ILenderCommitmentForwarder public immutable LENDER_COMMITMENT_FORWARDER;\n\n address public immutable POOL_ADDRESSES_PROVIDER;\n\n event RolloverLoanComplete(\n address borrower,\n uint256 originalLoanId,\n uint256 newLoanId,\n uint256 fundsRemaining\n );\n\n struct AcceptCommitmentArgs {\n uint256 commitmentId;\n uint256 principalAmount;\n uint256 collateralAmount;\n uint256 collateralTokenId;\n address collateralTokenAddress;\n uint16 interestRate;\n uint32 loanDuration;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(\n address _tellerV2,\n address _lenderCommitmentForwarder,\n address _poolAddressesProvider\n ) {\n TELLER_V2 = ITellerV2(_tellerV2);\n LENDER_COMMITMENT_FORWARDER = ILenderCommitmentForwarder(\n _lenderCommitmentForwarder\n );\n POOL_ADDRESSES_PROVIDER = _poolAddressesProvider;\n }\n\n modifier onlyFlashLoanPool() {\n require(\n msg.sender == address(POOL()),\n \"FlashRolloverLoan: Must be called by FlashLoanPool\"\n );\n\n _;\n }\n\n /*\n need to pass loanId and borrower \n */\n\n /**\n * @notice Allows a borrower to rollover a loan to a new commitment.\n * @param _loanId The bid id for the loan to repay\n * @param _flashLoanAmount The amount to flash borrow.\n * @param _acceptCommitmentArgs Arguments for the commitment to accept.\n * @return newLoanId_ The ID of the new loan created by accepting the commitment.\n */\n\n /*\n \nThe flash loan amount can naively be the exact amount needed to repay the old loan \n\nIf the new loan pays out (after fees) MORE than the aave loan amount+ fee) then borrower amount can be zero \n\n 1) I could solve for what the new loans payout (before fees and after fees) would NEED to be to make borrower amount 0...\n\n*/\n\n function rolloverLoanWithFlash(\n uint256 _loanId,\n uint256 _flashLoanAmount,\n uint256 _borrowerAmount, //an additional amount borrower may have to add\n AcceptCommitmentArgs calldata _acceptCommitmentArgs\n ) external returns (uint256 newLoanId_) {\n address borrower = TELLER_V2.getLoanBorrower(_loanId);\n require(borrower == msg.sender, \"CommitmentRolloverLoan: not borrower\");\n\n // Get lending token and balance before\n address lendingToken = TELLER_V2.getLoanLendingToken(_loanId);\n\n if (_borrowerAmount > 0) {\n IERC20(lendingToken).transferFrom(\n borrower,\n address(this),\n _borrowerAmount\n );\n }\n\n // Call 'Flash' on the vault to borrow funds and call tellerV2FlashCallback\n // This ultimately calls executeOperation\n IPool(POOL()).flashLoanSimple(\n address(this),\n lendingToken,\n _flashLoanAmount,\n abi.encode(\n RolloverCallbackArgs({\n loanId: _loanId,\n borrower: borrower,\n borrowerAmount: _borrowerAmount,\n acceptCommitmentArgs: abi.encode(_acceptCommitmentArgs)\n })\n ),\n 0 //referral code\n );\n }\n\n /*\n Notice: If collateral is being rolled over, it needs to be pre-approved from the borrower to the collateral manager \n */\n function executeOperation(\n address _flashToken,\n uint256 _flashAmount,\n uint256 _flashFees,\n address initiator,\n bytes calldata _data\n ) external virtual onlyFlashLoanPool returns (bool) {\n require(\n initiator == address(this),\n \"This contract must be the initiator\"\n );\n\n RolloverCallbackArgs memory _rolloverArgs = abi.decode(\n _data,\n (RolloverCallbackArgs)\n );\n\n uint256 repaymentAmount = _repayLoanFull(\n _rolloverArgs.loanId,\n _flashToken,\n _flashAmount\n );\n\n AcceptCommitmentArgs memory acceptCommitmentArgs = abi.decode(\n _rolloverArgs.acceptCommitmentArgs,\n (AcceptCommitmentArgs)\n );\n\n // Accept commitment and receive funds to this contract\n\n (uint256 newLoanId, uint256 acceptCommitmentAmount) = _acceptCommitment(\n _rolloverArgs.borrower,\n _flashToken,\n acceptCommitmentArgs\n );\n\n //approve the repayment for the flash loan\n IERC20Upgradeable(_flashToken).approve(\n address(POOL()),\n _flashAmount + _flashFees\n );\n\n uint256 fundsRemaining = acceptCommitmentAmount +\n _rolloverArgs.borrowerAmount -\n repaymentAmount -\n _flashFees;\n\n if (fundsRemaining > 0) {\n IERC20Upgradeable(_flashToken).transfer(\n _rolloverArgs.borrower,\n fundsRemaining\n );\n }\n\n emit RolloverLoanComplete(\n _rolloverArgs.borrower,\n _rolloverArgs.loanId,\n newLoanId,\n fundsRemaining\n );\n\n return true;\n }\n\n function _repayLoanFull(\n uint256 _bidId,\n address _principalToken,\n uint256 _repayAmount\n ) internal returns (uint256 repayAmount_) {\n uint256 fundsBeforeRepayment = IERC20Upgradeable(_principalToken)\n .balanceOf(address(this));\n \n\n IERC20Upgradeable(_principalToken).approve(\n address(TELLER_V2),\n _repayAmount\n );\n TELLER_V2.repayLoanFull(_bidId);\n\n uint256 fundsAfterRepayment = IERC20Upgradeable(_principalToken)\n .balanceOf(address(this));\n\n repayAmount_ = fundsBeforeRepayment - fundsAfterRepayment;\n }\n\n /**\n * @notice Internally accepts a commitment via the `LENDER_COMMITMENT_FORWARDER`.\n * @param _commitmentArgs Arguments required to accept a commitment.\n * @return bidId_ The ID of the bid associated with the accepted commitment.\n */\n function _acceptCommitment(\n address borrower,\n address principalToken,\n AcceptCommitmentArgs memory _commitmentArgs\n )\n internal\n virtual\n returns (uint256 bidId_, uint256 acceptCommitmentAmount_)\n {\n uint256 fundsBeforeAcceptCommitment = IERC20Upgradeable(principalToken)\n .balanceOf(address(this));\n\n bytes memory responseData = address(LENDER_COMMITMENT_FORWARDER)\n .functionCall(\n abi.encodePacked(\n abi.encodeWithSelector(\n ILenderCommitmentForwarder\n .acceptCommitmentWithRecipient\n .selector,\n _commitmentArgs.commitmentId,\n _commitmentArgs.principalAmount,\n _commitmentArgs.collateralAmount,\n _commitmentArgs.collateralTokenId,\n _commitmentArgs.collateralTokenAddress,\n address(this),\n _commitmentArgs.interestRate,\n _commitmentArgs.loanDuration\n ),\n borrower //cant be msg.sender because of the flash flow\n )\n );\n\n (bidId_) = abi.decode(responseData, (uint256));\n\n uint256 fundsAfterAcceptCommitment = IERC20Upgradeable(principalToken)\n .balanceOf(address(this));\n acceptCommitmentAmount_ =\n fundsAfterAcceptCommitment -\n fundsBeforeAcceptCommitment;\n }\n\n function ADDRESSES_PROVIDER() public view returns (IPoolAddressesProvider) {\n return IPoolAddressesProvider(POOL_ADDRESSES_PROVIDER);\n }\n\n function POOL() public view returns (IPool) {\n return IPool(ADDRESSES_PROVIDER().getPool());\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G2.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Contracts\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../libraries/NumbersLib.sol\";\n\n// Interfaces\nimport \"./FlashRolloverLoan_G1.sol\";\n\ncontract FlashRolloverLoan_G2 is FlashRolloverLoan_G1 {\n using AddressUpgradeable for address;\n using NumbersLib for uint256;\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(\n address _tellerV2,\n address _lenderCommitmentForwarder,\n address _poolAddressesProvider\n )\n FlashRolloverLoan_G1(\n _tellerV2,\n _lenderCommitmentForwarder,\n _poolAddressesProvider\n )\n {}\n\n /*\n\n This assumes that the flash amount will be the repayLoanFull amount !!\n\n */\n /**\n * @notice Calculates the amount for loan rollover, determining if the borrower owes or receives funds.\n * @param _loanId The ID of the loan to calculate the rollover amount for.\n * @param _commitmentArgs Arguments for the commitment.\n * @param _timestamp The timestamp for when the calculation is executed.\n \n */\n function calculateRolloverAmount(\n uint256 _loanId,\n AcceptCommitmentArgs calldata _commitmentArgs,\n uint16 _flashloanPremiumPct,\n uint256 _timestamp\n ) external view returns (uint256 _flashAmount, int256 _borrowerAmount) {\n Payment memory repayAmountOwed = TELLER_V2.calculateAmountOwed(\n _loanId,\n _timestamp\n );\n\n uint256 _marketId = _getMarketIdForCommitment(\n _commitmentArgs.commitmentId\n );\n uint16 marketFeePct = _getMarketFeePct(_marketId);\n uint16 protocolFeePct = _getProtocolFeePct();\n\n uint256 commitmentPrincipalRequested = _commitmentArgs.principalAmount;\n uint256 amountToMarketplace = commitmentPrincipalRequested.percent(\n marketFeePct\n );\n uint256 amountToProtocol = commitmentPrincipalRequested.percent(\n protocolFeePct\n );\n\n uint256 commitmentPrincipalReceived = commitmentPrincipalRequested -\n amountToMarketplace -\n amountToProtocol;\n\n // by default, we will flash exactly what we need to do relayLoanFull\n uint256 repayFullAmount = repayAmountOwed.principal +\n repayAmountOwed.interest;\n\n _flashAmount = repayFullAmount;\n uint256 _flashLoanFee = _flashAmount.percent(_flashloanPremiumPct);\n\n _borrowerAmount =\n int256(commitmentPrincipalReceived) -\n int256(repayFullAmount) -\n int256(_flashLoanFee);\n }\n\n /**\n * @notice Retrieves the market ID associated with a given commitment.\n * @param _commitmentId The ID of the commitment for which to fetch the market ID.\n * @return The ID of the market associated with the provided commitment.\n */\n function _getMarketIdForCommitment(\n uint256 _commitmentId\n ) internal view returns (uint256) {\n return LENDER_COMMITMENT_FORWARDER.getCommitmentMarketId(_commitmentId);\n }\n\n /**\n * @notice Fetches the marketplace fee percentage for a given market ID.\n * @param _marketId The ID of the market for which to fetch the fee percentage.\n * @return The marketplace fee percentage for the provided market ID.\n */\n function _getMarketFeePct(\n uint256 _marketId\n ) internal view returns (uint16) {\n address _marketRegistryAddress = ITellerV2Storage(address(TELLER_V2))\n .marketRegistry();\n\n return\n IMarketRegistry(_marketRegistryAddress).getMarketplaceFee(\n _marketId\n );\n }\n\n /**\n * @notice Fetches the protocol fee percentage from the Teller V2 protocol.\n * @return The protocol fee percentage as defined in the Teller V2 protocol.\n */\n function _getProtocolFeePct() internal view returns (uint16) {\n return IProtocolFee(address(TELLER_V2)).protocolFee();\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan_G3.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Contracts\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n// Interfaces\nimport \"../../interfaces/ITellerV2.sol\";\nimport \"../../interfaces/IProtocolFee.sol\";\nimport \"../../interfaces/ITellerV2Storage.sol\";\nimport \"../../interfaces/IMarketRegistry.sol\";\nimport \"../../interfaces/ILenderCommitmentForwarder.sol\";\nimport \"../../interfaces/IFlashRolloverLoan.sol\";\nimport \"../../libraries/NumbersLib.sol\";\n\nimport { IPool } from \"../../interfaces/aave/IPool.sol\";\nimport { IFlashLoanSimpleReceiver } from \"../../interfaces/aave/IFlashLoanSimpleReceiver.sol\";\nimport { IPoolAddressesProvider } from \"../../interfaces/aave/IPoolAddressesProvider.sol\";\n\ncontract FlashRolloverLoan_G3 is IFlashLoanSimpleReceiver, IFlashRolloverLoan {\n using AddressUpgradeable for address;\n using NumbersLib for uint256;\n\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n ITellerV2 public immutable TELLER_V2;\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n ILenderCommitmentForwarder public immutable LENDER_COMMITMENT_FORWARDER;\n\n address public immutable POOL_ADDRESSES_PROVIDER;\n\n event RolloverLoanComplete(\n address borrower,\n uint256 originalLoanId,\n uint256 newLoanId,\n uint256 fundsRemaining\n );\n\n struct AcceptCommitmentArgs {\n uint256 commitmentId;\n uint256 principalAmount;\n uint256 collateralAmount;\n uint256 collateralTokenId;\n address collateralTokenAddress;\n uint16 interestRate;\n uint32 loanDuration;\n bytes32[] merkleProof; //empty array if not used\n }\n\n /**\n *\n * @notice Initializes the FlashRolloverLoan with necessary contract addresses.\n *\n * @dev Using a custom OpenZeppelin upgrades tag. Ensure the constructor logic is safe for upgrades.\n *\n * @param _tellerV2 The address of the TellerV2 contract.\n * @param _lenderCommitmentForwarder The address of the LenderCommitmentForwarder contract.\n * @param _poolAddressesProvider The address of the PoolAddressesProvider.\n */\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(\n address _tellerV2,\n address _lenderCommitmentForwarder,\n address _poolAddressesProvider\n ) {\n TELLER_V2 = ITellerV2(_tellerV2);\n LENDER_COMMITMENT_FORWARDER = ILenderCommitmentForwarder(\n _lenderCommitmentForwarder\n );\n POOL_ADDRESSES_PROVIDER = _poolAddressesProvider;\n }\n\n modifier onlyFlashLoanPool() {\n require(\n msg.sender == address(POOL()),\n \"FlashRolloverLoan: Must be called by FlashLoanPool\"\n );\n\n _;\n }\n\n /**\n *\n * @notice Allows the borrower to rollover their existing loan using a flash loan mechanism.\n * The borrower might also provide an additional amount during the rollover.\n *\n * @dev The function first verifies that the caller is the borrower of the loan.\n * It then optionally transfers the additional amount specified by the borrower.\n * A flash loan is then taken from the pool to facilitate the rollover and\n * a callback is executed for further operations.\n *\n * @param _loanId Identifier of the existing loan to be rolled over.\n * @param _flashLoanAmount Amount of flash loan to be borrowed for the rollover.\n * @param _borrowerAmount Additional amount that the borrower may want to add during rollover.\n * @param _acceptCommitmentArgs Commitment arguments that might be necessary for internal operations.\n *\n * @return newLoanId_ Identifier of the new loan post rollover.\n */\n function rolloverLoanWithFlash(\n uint256 _loanId,\n uint256 _flashLoanAmount,\n uint256 _borrowerAmount, //an additional amount borrower may have to add\n AcceptCommitmentArgs calldata _acceptCommitmentArgs\n ) external returns (uint256 newLoanId_) {\n address borrower = TELLER_V2.getLoanBorrower(_loanId);\n require(borrower == msg.sender, \"CommitmentRolloverLoan: not borrower\");\n\n // Get lending token and balance before\n address lendingToken = TELLER_V2.getLoanLendingToken(_loanId);\n\n if (_borrowerAmount > 0) {\n IERC20(lendingToken).transferFrom(\n borrower,\n address(this),\n _borrowerAmount\n );\n }\n\n // Call 'Flash' on the vault to borrow funds and call tellerV2FlashCallback\n // This ultimately calls executeOperation\n IPool(POOL()).flashLoanSimple(\n address(this),\n lendingToken,\n _flashLoanAmount,\n abi.encode(\n RolloverCallbackArgs({\n loanId: _loanId,\n borrower: borrower,\n borrowerAmount: _borrowerAmount,\n acceptCommitmentArgs: abi.encode(_acceptCommitmentArgs)\n })\n ),\n 0 //referral code\n );\n }\n\n /**\n *\n * @notice Callback function that is triggered by Aave during the flash loan process.\n * This function handles the logic to use the borrowed funds to rollover the loan,\n * make necessary repayments, and manage the loan commitments.\n *\n * @dev The function ensures the initiator is this contract, decodes the data provided by\n * the flash loan call, repays the original loan in full, accepts new loan commitments,\n * approves the repayment for the flash loan and then handles any remaining funds.\n * This function should only be called by the FlashLoanPool as ensured by the `onlyFlashLoanPool` modifier.\n *\n * @param _flashToken The token in which the flash loan is borrowed.\n * @param _flashAmount The amount of tokens borrowed via the flash loan.\n * @param _flashFees The fees associated with the flash loan to be repaid to Aave.\n * @param _initiator The address initiating the flash loan (must be this contract).\n * @param _data Encoded data containing necessary information for loan rollover.\n *\n * @return Returns true if the operation was successful.\n */\n function executeOperation(\n address _flashToken,\n uint256 _flashAmount,\n uint256 _flashFees,\n address _initiator,\n bytes calldata _data\n ) external virtual onlyFlashLoanPool returns (bool) {\n require(\n _initiator == address(this),\n \"This contract must be the initiator\"\n );\n\n RolloverCallbackArgs memory _rolloverArgs = abi.decode(\n _data,\n (RolloverCallbackArgs)\n );\n\n uint256 repaymentAmount = _repayLoanFull(\n _rolloverArgs.loanId,\n _flashToken,\n _flashAmount\n );\n\n AcceptCommitmentArgs memory acceptCommitmentArgs = abi.decode(\n _rolloverArgs.acceptCommitmentArgs,\n (AcceptCommitmentArgs)\n );\n\n // Accept commitment and receive funds to this contract\n\n (uint256 newLoanId, uint256 acceptCommitmentAmount) = _acceptCommitment(\n _rolloverArgs.borrower,\n _flashToken,\n acceptCommitmentArgs\n );\n\n //approve the repayment for the flash loan\n IERC20Upgradeable(_flashToken).approve(\n address(POOL()),\n _flashAmount + _flashFees\n );\n\n uint256 fundsRemaining = acceptCommitmentAmount +\n _rolloverArgs.borrowerAmount -\n repaymentAmount -\n _flashFees;\n\n if (fundsRemaining > 0) {\n IERC20Upgradeable(_flashToken).transfer(\n _rolloverArgs.borrower,\n fundsRemaining\n );\n }\n\n emit RolloverLoanComplete(\n _rolloverArgs.borrower,\n _rolloverArgs.loanId,\n newLoanId,\n fundsRemaining\n );\n\n return true;\n }\n\n /**\n *\n *\n * @notice Internal function that repays a loan in full on behalf of this contract.\n *\n * @dev The function first calculates the funds held by the contract before repayment, then approves\n * the repayment amount to the TellerV2 contract and finally repays the loan in full.\n *\n * @param _bidId Identifier of the loan to be repaid.\n * @param _principalToken The token in which the loan was originated.\n * @param _repayAmount The amount to be repaid.\n *\n * @return repayAmount_ The actual amount that was used for repayment.\n */\n function _repayLoanFull(\n uint256 _bidId,\n address _principalToken,\n uint256 _repayAmount\n ) internal returns (uint256 repayAmount_) {\n uint256 fundsBeforeRepayment = IERC20Upgradeable(_principalToken)\n .balanceOf(address(this));\n\n IERC20Upgradeable(_principalToken).approve(\n address(TELLER_V2),\n _repayAmount\n );\n TELLER_V2.repayLoanFull(_bidId);\n\n uint256 fundsAfterRepayment = IERC20Upgradeable(_principalToken)\n .balanceOf(address(this));\n\n repayAmount_ = fundsBeforeRepayment - fundsAfterRepayment;\n }\n\n /**\n *\n *\n * @notice Accepts a loan commitment using either a Merkle proof or standard method.\n *\n * @dev The function first checks if a Merkle proof is provided, based on which it calls the relevant\n * `acceptCommitment` function in the LenderCommitmentForwarder contract.\n *\n * @param borrower The address of the borrower for whom the commitment is being accepted.\n * @param principalToken The token in which the loan is being accepted.\n * @param _commitmentArgs The arguments necessary for accepting the commitment.\n *\n * @return bidId_ Identifier of the accepted loan.\n * @return acceptCommitmentAmount_ The amount received from accepting the commitment.\n */\n function _acceptCommitment(\n address borrower,\n address principalToken,\n AcceptCommitmentArgs memory _commitmentArgs\n )\n internal\n virtual\n returns (uint256 bidId_, uint256 acceptCommitmentAmount_)\n {\n uint256 fundsBeforeAcceptCommitment = IERC20Upgradeable(principalToken)\n .balanceOf(address(this));\n\n bool usingMerkleProof = _commitmentArgs.merkleProof.length > 0;\n\n if (usingMerkleProof) {\n bytes memory responseData = address(LENDER_COMMITMENT_FORWARDER)\n .functionCall(\n abi.encodePacked(\n abi.encodeWithSelector(\n ILenderCommitmentForwarder\n .acceptCommitmentWithRecipientAndProof\n .selector,\n _commitmentArgs.commitmentId,\n _commitmentArgs.principalAmount,\n _commitmentArgs.collateralAmount,\n _commitmentArgs.collateralTokenId,\n _commitmentArgs.collateralTokenAddress,\n address(this),\n _commitmentArgs.interestRate,\n _commitmentArgs.loanDuration,\n _commitmentArgs.merkleProof\n ),\n borrower //cant be msg.sender because of the flash flow\n )\n );\n\n (bidId_) = abi.decode(responseData, (uint256));\n } else {\n bytes memory responseData = address(LENDER_COMMITMENT_FORWARDER)\n .functionCall(\n abi.encodePacked(\n abi.encodeWithSelector(\n ILenderCommitmentForwarder\n .acceptCommitmentWithRecipient\n .selector,\n _commitmentArgs.commitmentId,\n _commitmentArgs.principalAmount,\n _commitmentArgs.collateralAmount,\n _commitmentArgs.collateralTokenId,\n _commitmentArgs.collateralTokenAddress,\n address(this),\n _commitmentArgs.interestRate,\n _commitmentArgs.loanDuration\n ),\n borrower //cant be msg.sender because of the flash flow\n )\n );\n\n (bidId_) = abi.decode(responseData, (uint256));\n }\n\n uint256 fundsAfterAcceptCommitment = IERC20Upgradeable(principalToken)\n .balanceOf(address(this));\n acceptCommitmentAmount_ =\n fundsAfterAcceptCommitment -\n fundsBeforeAcceptCommitment;\n }\n\n function ADDRESSES_PROVIDER() public view returns (IPoolAddressesProvider) {\n return IPoolAddressesProvider(POOL_ADDRESSES_PROVIDER);\n }\n\n function POOL() public view returns (IPool) {\n return IPool(ADDRESSES_PROVIDER().getPool());\n }\n\n /**\n * @notice Calculates the amount for loan rollover, determining if the borrower owes or receives funds.\n * @param _loanId The ID of the loan to calculate the rollover amount for.\n * @param _commitmentArgs Arguments for the commitment.\n * @param _timestamp The timestamp for when the calculation is executed.\n \n */\n function calculateRolloverAmount(\n uint256 _loanId,\n AcceptCommitmentArgs calldata _commitmentArgs,\n uint16 _flashloanPremiumPct,\n uint256 _timestamp\n ) external view returns (uint256 _flashAmount, int256 _borrowerAmount) {\n Payment memory repayAmountOwed = TELLER_V2.calculateAmountOwed(\n _loanId,\n _timestamp\n );\n\n uint256 _marketId = _getMarketIdForCommitment(\n _commitmentArgs.commitmentId\n );\n uint16 marketFeePct = _getMarketFeePct(_marketId);\n uint16 protocolFeePct = _getProtocolFeePct();\n\n uint256 commitmentPrincipalRequested = _commitmentArgs.principalAmount;\n uint256 amountToMarketplace = commitmentPrincipalRequested.percent(\n marketFeePct\n );\n uint256 amountToProtocol = commitmentPrincipalRequested.percent(\n protocolFeePct\n );\n\n uint256 commitmentPrincipalReceived = commitmentPrincipalRequested -\n amountToMarketplace -\n amountToProtocol;\n\n // by default, we will flash exactly what we need to do relayLoanFull\n uint256 repayFullAmount = repayAmountOwed.principal +\n repayAmountOwed.interest;\n\n _flashAmount = repayFullAmount;\n uint256 _flashLoanFee = _flashAmount.percent(_flashloanPremiumPct);\n\n _borrowerAmount =\n int256(commitmentPrincipalReceived) -\n int256(repayFullAmount) -\n int256(_flashLoanFee);\n }\n\n /**\n * @notice Retrieves the market ID associated with a given commitment.\n * @param _commitmentId The ID of the commitment for which to fetch the market ID.\n * @return The ID of the market associated with the provided commitment.\n */\n function _getMarketIdForCommitment(uint256 _commitmentId)\n internal\n view\n returns (uint256)\n {\n return LENDER_COMMITMENT_FORWARDER.getCommitmentMarketId(_commitmentId);\n }\n\n /**\n * @notice Fetches the marketplace fee percentage for a given market ID.\n * @param _marketId The ID of the market for which to fetch the fee percentage.\n * @return The marketplace fee percentage for the provided market ID.\n */\n function _getMarketFeePct(uint256 _marketId)\n internal\n view\n returns (uint16)\n {\n address _marketRegistryAddress = ITellerV2Storage(address(TELLER_V2))\n .marketRegistry();\n\n return\n IMarketRegistry(_marketRegistryAddress).getMarketplaceFee(\n _marketId\n );\n }\n\n /**\n * @notice Fetches the protocol fee percentage from the Teller V2 protocol.\n * @return The protocol fee percentage as defined in the Teller V2 protocol.\n */\n function _getProtocolFeePct() internal view returns (uint16) {\n return IProtocolFee(address(TELLER_V2)).protocolFee();\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/extensions/FlashRolloverLoan.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"../../interfaces/IFlashRolloverLoan.sol\";\nimport \"./FlashRolloverLoan_G3.sol\";\n\ncontract FlashRolloverLoan is IFlashRolloverLoan, FlashRolloverLoan_G3 {\n constructor(\n address _tellerV2,\n address _lenderCommitmentForwarder,\n address _poolAddressesProvider\n )\n FlashRolloverLoan_G3(\n _tellerV2,\n _lenderCommitmentForwarder,\n _poolAddressesProvider\n )\n {}\n}\n" + }, + "contracts/LenderCommitmentForwarder/LenderCommitmentForwarder_G1.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"../TellerV2MarketForwarder_G1.sol\";\n\n// Interfaces\nimport \"../interfaces/ICollateralManager.sol\";\nimport { Collateral, CollateralType } from \"../interfaces/escrow/ICollateralEscrowV1.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol\";\n\n// Libraries\nimport { MathUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol\";\n\ncontract LenderCommitmentForwarder_G1 is TellerV2MarketForwarder_G1 {\n using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n\n enum CommitmentCollateralType {\n NONE, // no collateral required\n ERC20,\n ERC721,\n ERC1155,\n ERC721_ANY_ID,\n ERC1155_ANY_ID,\n ERC721_MERKLE_PROOF,\n ERC1155_MERKLE_PROOF\n }\n\n /**\n * @notice Details about a lender's capital commitment.\n * @param maxPrincipal Amount of tokens being committed by the lender. Max amount that can be loaned.\n * @param expiration Expiration time in seconds, when the commitment expires.\n * @param maxDuration Length of time, in seconds that the lender's capital can be lent out for.\n * @param minInterestRate Minimum Annual percentage to be applied for loans using the lender's capital.\n * @param collateralTokenAddress The address for the token contract that must be used to provide collateral for loans for this commitment.\n * @param maxPrincipalPerCollateralAmount The amount of principal that can be used for a loan per each unit of collateral, expanded additionally by principal decimals.\n * @param collateralTokenType The type of asset of the collateralTokenAddress (ERC20, ERC721, or ERC1155).\n * @param lender The address of the lender for this commitment.\n * @param marketId The market id for this commitment.\n * @param principalTokenAddress The address for the token contract that will be used to provide principal for loans of this commitment.\n */\n struct Commitment {\n uint256 maxPrincipal;\n uint32 expiration;\n uint32 maxDuration;\n uint16 minInterestRate;\n address collateralTokenAddress;\n uint256 collateralTokenId; //we use this for the MerkleRootHash for type ERC721_MERKLE_PROOF\n uint256 maxPrincipalPerCollateralAmount;\n CommitmentCollateralType collateralTokenType;\n address lender;\n uint256 marketId;\n address principalTokenAddress;\n }\n\n // CommitmentId => commitment\n mapping(uint256 => Commitment) public commitments;\n\n uint256 commitmentCount;\n\n //https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/structs/EnumerableSetUpgradeable.sol\n mapping(uint256 => EnumerableSetUpgradeable.AddressSet)\n internal commitmentBorrowersList;\n\n mapping(uint256 => uint256) public commitmentPrincipalAccepted;\n\n /**\n * @notice This event is emitted when a lender's commitment is created.\n * @param lender The address of the lender.\n * @param marketId The Id of the market the commitment applies to.\n * @param lendingToken The address of the asset being committed.\n * @param tokenAmount The amount of the asset being committed.\n */\n event CreatedCommitment(\n uint256 indexed commitmentId,\n address lender,\n uint256 marketId,\n address lendingToken,\n uint256 tokenAmount\n );\n\n /**\n * @notice This event is emitted when a lender's commitment is updated.\n * @param commitmentId The id of the commitment that was updated.\n * @param lender The address of the lender.\n * @param marketId The Id of the market the commitment applies to.\n * @param lendingToken The address of the asset being committed.\n * @param tokenAmount The amount of the asset being committed.\n */\n event UpdatedCommitment(\n uint256 indexed commitmentId,\n address lender,\n uint256 marketId,\n address lendingToken,\n uint256 tokenAmount\n );\n\n /**\n * @notice This event is emitted when the allowed borrowers for a commitment is updated.\n * @param commitmentId The id of the commitment that was updated.\n */\n event UpdatedCommitmentBorrowers(uint256 indexed commitmentId);\n\n /**\n * @notice This event is emitted when a lender's commitment has been deleted.\n * @param commitmentId The id of the commitment that was deleted.\n */\n event DeletedCommitment(uint256 indexed commitmentId);\n\n /**\n * @notice This event is emitted when a lender's commitment is exercised for a loan.\n * @param commitmentId The id of the commitment that was exercised.\n * @param borrower The address of the borrower.\n * @param tokenAmount The amount of the asset being committed.\n * @param bidId The bid id for the loan from TellerV2.\n */\n event ExercisedCommitment(\n uint256 indexed commitmentId,\n address borrower,\n uint256 tokenAmount,\n uint256 bidId\n );\n\n error InsufficientCommitmentAllocation(\n uint256 allocated,\n uint256 requested\n );\n error InsufficientBorrowerCollateral(uint256 required, uint256 actual);\n\n /** Modifiers **/\n\n modifier commitmentLender(uint256 _commitmentId) {\n require(\n commitments[_commitmentId].lender == _msgSender(),\n \"unauthorized commitment lender\"\n );\n _;\n }\n\n function validateCommitment(Commitment storage _commitment) internal {\n require(\n _commitment.expiration > uint32(block.timestamp),\n \"expired commitment\"\n );\n require(\n _commitment.maxPrincipal > 0,\n \"commitment principal allocation 0\"\n );\n\n if (_commitment.collateralTokenType != CommitmentCollateralType.NONE) {\n require(\n _commitment.maxPrincipalPerCollateralAmount > 0,\n \"commitment collateral ratio 0\"\n );\n\n if (\n _commitment.collateralTokenType ==\n CommitmentCollateralType.ERC20\n ) {\n require(\n _commitment.collateralTokenId == 0,\n \"commitment collateral token id must be 0 for ERC20\"\n );\n }\n }\n }\n\n /** External Functions **/\n\n constructor(address _protocolAddress, address _marketRegistry)\n TellerV2MarketForwarder_G1(_protocolAddress, _marketRegistry)\n {}\n\n /**\n * @notice Creates a loan commitment from a lender for a market.\n * @param _commitment The new commitment data expressed as a struct\n * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment\n * @return commitmentId_ returns the commitmentId for the created commitment\n */\n function createCommitment(\n Commitment calldata _commitment,\n address[] calldata _borrowerAddressList\n ) public returns (uint256 commitmentId_) {\n commitmentId_ = commitmentCount++;\n\n require(\n _commitment.lender == _msgSender(),\n \"unauthorized commitment creator\"\n );\n\n commitments[commitmentId_] = _commitment;\n\n //make sure the commitment data adheres to required specifications and limits\n validateCommitment(commitments[commitmentId_]);\n\n //the borrower allowlists is in a different storage space so we append them to the array with this method s\n _addBorrowersToCommitmentAllowlist(commitmentId_, _borrowerAddressList);\n\n emit CreatedCommitment(\n commitmentId_,\n _commitment.lender,\n _commitment.marketId,\n _commitment.principalTokenAddress,\n _commitment.maxPrincipal\n );\n }\n\n /**\n * @notice Updates the commitment of a lender to a market.\n * @param _commitmentId The Id of the commitment to update.\n * @param _commitment The new commitment data expressed as a struct\n */\n function updateCommitment(\n uint256 _commitmentId,\n Commitment calldata _commitment\n ) public commitmentLender(_commitmentId) {\n require(\n _commitment.lender == _msgSender(),\n \"Commitment lender cannot be updated.\"\n );\n\n require(\n _commitment.principalTokenAddress ==\n commitments[_commitmentId].principalTokenAddress,\n \"Principal token address cannot be updated.\"\n );\n require(\n _commitment.marketId == commitments[_commitmentId].marketId,\n \"Market Id cannot be updated.\"\n );\n\n commitments[_commitmentId] = _commitment;\n\n //make sure the commitment data still adheres to required specifications and limits\n validateCommitment(commitments[_commitmentId]);\n\n emit UpdatedCommitment(\n _commitmentId,\n _commitment.lender,\n _commitment.marketId,\n _commitment.principalTokenAddress,\n _commitment.maxPrincipal\n );\n }\n\n /**\n * @notice Updates the borrowers allowed to accept a commitment\n * @param _commitmentId The Id of the commitment to update.\n * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment\n */\n function addCommitmentBorrowers(\n uint256 _commitmentId,\n address[] calldata _borrowerAddressList\n ) public commitmentLender(_commitmentId) {\n _addBorrowersToCommitmentAllowlist(_commitmentId, _borrowerAddressList);\n }\n\n /**\n * @notice Updates the borrowers allowed to accept a commitment\n * @param _commitmentId The Id of the commitment to update.\n * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment\n */\n function removeCommitmentBorrowers(\n uint256 _commitmentId,\n address[] calldata _borrowerAddressList\n ) public commitmentLender(_commitmentId) {\n _removeBorrowersFromCommitmentAllowlist(\n _commitmentId,\n _borrowerAddressList\n );\n }\n\n /**\n * @notice Adds a borrower to the allowlist for a commmitment.\n * @param _commitmentId The id of the commitment that will allow the new borrower\n * @param _borrowerArray the address array of the borrowers that will be allowed to accept loans using the commitment\n */\n function _addBorrowersToCommitmentAllowlist(\n uint256 _commitmentId,\n address[] calldata _borrowerArray\n ) internal {\n for (uint256 i = 0; i < _borrowerArray.length; i++) {\n commitmentBorrowersList[_commitmentId].add(_borrowerArray[i]);\n }\n emit UpdatedCommitmentBorrowers(_commitmentId);\n }\n\n /**\n * @notice Removes a borrower to the allowlist for a commmitment.\n * @param _commitmentId The id of the commitment that will allow the new borrower\n * @param _borrowerArray the address array of the borrowers that will be allowed to accept loans using the commitment\n */\n function _removeBorrowersFromCommitmentAllowlist(\n uint256 _commitmentId,\n address[] calldata _borrowerArray\n ) internal {\n for (uint256 i = 0; i < _borrowerArray.length; i++) {\n commitmentBorrowersList[_commitmentId].remove(_borrowerArray[i]);\n }\n emit UpdatedCommitmentBorrowers(_commitmentId);\n }\n\n /**\n * @notice Removes the commitment of a lender to a market.\n * @param _commitmentId The id of the commitment to delete.\n */\n function deleteCommitment(uint256 _commitmentId)\n public\n commitmentLender(_commitmentId)\n {\n delete commitments[_commitmentId];\n delete commitmentBorrowersList[_commitmentId];\n emit DeletedCommitment(_commitmentId);\n }\n\n /**\n * @notice Accept the commitment to submitBid and acceptBid using the funds\n * @dev LoanDuration must be longer than the market payment cycle\n * @param _commitmentId The id of the commitment being accepted.\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId of collateral to use for the loan if ERC721 or ERC1155.\n * @param _collateralTokenAddress The contract address to use for the loan collateral tokens.\n * @param _interestRate The interest rate APY to use for the loan in basis points.\n * @param _loanDuration The overall duration for the loan. Must be longer than market payment cycle duration.\n * @return bidId The ID of the loan that was created on TellerV2\n */\n function acceptCommitment(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n uint16 _interestRate,\n uint32 _loanDuration\n ) external returns (uint256 bidId) {\n require(\n commitments[_commitmentId].collateralTokenType <=\n CommitmentCollateralType.ERC1155_ANY_ID,\n \"Invalid commitment collateral type\"\n );\n\n return\n _acceptCommitment(\n _commitmentId,\n _principalAmount,\n _collateralAmount,\n _collateralTokenId,\n _collateralTokenAddress,\n _interestRate,\n _loanDuration\n );\n }\n\n /**\n * @notice Accept the commitment to submitBid and acceptBid using the funds\n * @dev LoanDuration must be longer than the market payment cycle\n * @param _commitmentId The id of the commitment being accepted.\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId of collateral to use for the loan if ERC721 or ERC1155.\n * @param _collateralTokenAddress The contract address to use for the loan collateral tokens.\n * @param _interestRate The interest rate APY to use for the loan in basis points.\n * @param _loanDuration The overall duration for the loan. Must be longer than market payment cycle duration.\n * @param _merkleProof An array of bytes32 which are the roots down the merkle tree, the merkle proof.\n * @return bidId The ID of the loan that was created on TellerV2\n */\n function acceptCommitmentWithProof(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n uint16 _interestRate,\n uint32 _loanDuration,\n bytes32[] calldata _merkleProof\n ) external returns (uint256 bidId) {\n require(\n commitments[_commitmentId].collateralTokenType ==\n CommitmentCollateralType.ERC721_MERKLE_PROOF ||\n commitments[_commitmentId].collateralTokenType ==\n CommitmentCollateralType.ERC1155_MERKLE_PROOF,\n \"Invalid commitment collateral type\"\n );\n\n bytes32 _merkleRoot = bytes32(\n commitments[_commitmentId].collateralTokenId\n );\n bytes32 _leaf = keccak256(abi.encodePacked(_collateralTokenId));\n\n //make sure collateral token id is a leaf within the proof\n require(\n MerkleProofUpgradeable.verifyCalldata(\n _merkleProof,\n _merkleRoot,\n _leaf\n ),\n \"Invalid proof\"\n );\n\n return\n _acceptCommitment(\n _commitmentId,\n _principalAmount,\n _collateralAmount,\n _collateralTokenId,\n _collateralTokenAddress,\n _interestRate,\n _loanDuration\n );\n }\n\n /**\n * @notice Accept the commitment to submitBid and acceptBid using the funds\n * @dev LoanDuration must be longer than the market payment cycle\n * @param _commitmentId The id of the commitment being accepted.\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId of collateral to use for the loan if ERC721 or ERC1155.\n * @param _collateralTokenAddress The contract address to use for the loan collateral tokens.\n * @param _interestRate The interest rate APY to use for the loan in basis points.\n * @param _loanDuration The overall duration for the loan. Must be longer than market payment cycle duration.\n * @return bidId The ID of the loan that was created on TellerV2\n */\n function _acceptCommitment(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n uint16 _interestRate,\n uint32 _loanDuration\n ) internal returns (uint256 bidId) {\n address borrower = _msgSender();\n\n Commitment storage commitment = commitments[_commitmentId];\n\n //make sure the commitment data adheres to required specifications and limits\n validateCommitment(commitment);\n\n //the collateral token of the commitment should be the same as the acceptor expects\n require(\n _collateralTokenAddress == commitment.collateralTokenAddress,\n \"Mismatching collateral token\"\n );\n //the interest rate must be at least as high has the commitment demands. The borrower can use a higher interest rate although that would not be beneficial to the borrower.\n require(\n _interestRate >= commitment.minInterestRate,\n \"Invalid interest rate\"\n );\n //the loan duration must be less than the commitment max loan duration. The lender who made the commitment expects the money to be returned before this window.\n require(\n _loanDuration <= commitment.maxDuration,\n \"Invalid loan max duration\"\n );\n\n require(\n commitmentPrincipalAccepted[bidId] <= commitment.maxPrincipal,\n \"Invalid loan max principal\"\n );\n\n require(\n commitmentBorrowersList[_commitmentId].length() == 0 ||\n commitmentBorrowersList[_commitmentId].contains(borrower),\n \"unauthorized commitment borrower\"\n );\n //require that the borrower accepting the commitment cannot borrow more than the commitments max principal\n if (_principalAmount > commitment.maxPrincipal) {\n revert InsufficientCommitmentAllocation({\n allocated: commitment.maxPrincipal,\n requested: _principalAmount\n });\n }\n\n uint256 requiredCollateral = getRequiredCollateral(\n _principalAmount,\n commitment.maxPrincipalPerCollateralAmount,\n commitment.collateralTokenType,\n commitment.collateralTokenAddress,\n commitment.principalTokenAddress\n );\n\n if (_collateralAmount < requiredCollateral) {\n revert InsufficientBorrowerCollateral({\n required: requiredCollateral,\n actual: _collateralAmount\n });\n }\n\n //ERC721 assets must have a quantity of 1\n if (\n commitment.collateralTokenType == CommitmentCollateralType.ERC721 ||\n commitment.collateralTokenType ==\n CommitmentCollateralType.ERC721_ANY_ID ||\n commitment.collateralTokenType ==\n CommitmentCollateralType.ERC721_MERKLE_PROOF\n ) {\n require(\n _collateralAmount == 1,\n \"invalid commitment collateral amount for ERC721\"\n );\n }\n\n //ERC721 and ERC1155 types strictly enforce a specific token Id. ERC721_ANY and ERC1155_ANY do not.\n if (\n commitment.collateralTokenType == CommitmentCollateralType.ERC721 ||\n commitment.collateralTokenType == CommitmentCollateralType.ERC1155\n ) {\n require(\n commitment.collateralTokenId == _collateralTokenId,\n \"invalid commitment collateral tokenId\"\n );\n }\n\n commitmentPrincipalAccepted[_commitmentId] += _principalAmount;\n\n require(\n commitmentPrincipalAccepted[_commitmentId] <=\n commitment.maxPrincipal,\n \"Exceeds max principal of commitment\"\n );\n\n bidId = _submitBidFromCommitment(\n borrower,\n commitment.marketId,\n commitment.principalTokenAddress,\n _principalAmount,\n commitment.collateralTokenAddress,\n _collateralAmount,\n _collateralTokenId,\n commitment.collateralTokenType,\n _loanDuration,\n _interestRate\n );\n\n _acceptBid(bidId, commitment.lender);\n\n emit ExercisedCommitment(\n _commitmentId,\n borrower,\n _principalAmount,\n bidId\n );\n }\n\n /**\n * @notice Calculate the amount of collateral required to borrow a loan with _principalAmount of principal\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _maxPrincipalPerCollateralAmount The ratio for the amount of principal that can be borrowed for each amount of collateral. This is expanded additionally by the principal decimals.\n * @param _collateralTokenType The type of collateral for the loan either ERC20, ERC721, ERC1155, or None.\n * @param _collateralTokenAddress The contract address for the collateral for the loan.\n * @param _principalTokenAddress The contract address for the principal for the loan.\n */\n function getRequiredCollateral(\n uint256 _principalAmount,\n uint256 _maxPrincipalPerCollateralAmount,\n CommitmentCollateralType _collateralTokenType,\n address _collateralTokenAddress,\n address _principalTokenAddress\n ) public view virtual returns (uint256) {\n if (_collateralTokenType == CommitmentCollateralType.NONE) {\n return 0;\n }\n\n uint8 collateralDecimals;\n uint8 principalDecimals = IERC20MetadataUpgradeable(\n _principalTokenAddress\n ).decimals();\n\n if (_collateralTokenType == CommitmentCollateralType.ERC20) {\n collateralDecimals = IERC20MetadataUpgradeable(\n _collateralTokenAddress\n ).decimals();\n }\n\n /*\n * The principalAmount is expanded by (collateralDecimals+principalDecimals) to increase precision\n * and then it is divided by _maxPrincipalPerCollateralAmount which should already been expanded by principalDecimals\n */\n return\n MathUpgradeable.mulDiv(\n _principalAmount,\n (10**(collateralDecimals + principalDecimals)),\n _maxPrincipalPerCollateralAmount,\n MathUpgradeable.Rounding.Up\n );\n }\n\n /**\n * @notice Return the array of borrowers that are allowlisted for a commitment\n * @param _commitmentId The commitment id for the commitment to query.\n * @return borrowers_ An array of addresses restricted to accept the commitment. Empty array means unrestricted.\n */\n function getCommitmentBorrowers(uint256 _commitmentId)\n external\n view\n returns (address[] memory borrowers_)\n {\n borrowers_ = commitmentBorrowersList[_commitmentId].values();\n }\n\n /**\n * @notice Internal function to submit a bid to the lending protocol using a commitment\n * @param _borrower The address of the borrower for the loan.\n * @param _marketId The id for the market of the loan in the lending protocol.\n * @param _principalTokenAddress The contract address for the principal token.\n * @param _principalAmount The amount of principal to borrow for the loan.\n * @param _collateralTokenAddress The contract address for the collateral token.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId for the collateral (if it is ERC721 or ERC1155).\n * @param _collateralTokenType The type of collateral token (ERC20,ERC721,ERC1177,None).\n * @param _loanDuration The duration of the loan in seconds delta. Must be longer than loan payment cycle for the market.\n * @param _interestRate The amount of interest APY for the loan expressed in basis points.\n */\n function _submitBidFromCommitment(\n address _borrower,\n uint256 _marketId,\n address _principalTokenAddress,\n uint256 _principalAmount,\n address _collateralTokenAddress,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n CommitmentCollateralType _collateralTokenType,\n uint32 _loanDuration,\n uint16 _interestRate\n ) internal returns (uint256 bidId) {\n CreateLoanArgs memory createLoanArgs;\n createLoanArgs.marketId = _marketId;\n createLoanArgs.lendingToken = _principalTokenAddress;\n createLoanArgs.principal = _principalAmount;\n createLoanArgs.duration = _loanDuration;\n createLoanArgs.interestRate = _interestRate;\n\n Collateral[] memory collateralInfo;\n if (_collateralTokenType != CommitmentCollateralType.NONE) {\n collateralInfo = new Collateral[](1);\n collateralInfo[0] = Collateral({\n _collateralType: _getEscrowCollateralType(_collateralTokenType),\n _tokenId: _collateralTokenId,\n _amount: _collateralAmount,\n _collateralAddress: _collateralTokenAddress\n });\n }\n\n bidId = _submitBidWithCollateral(\n createLoanArgs,\n collateralInfo,\n _borrower\n );\n }\n\n /**\n * @notice Return the collateral type based on the commitmentcollateral type. Collateral type is used in the base lending protocol.\n * @param _type The type of collateral to be used for the loan.\n */\n function _getEscrowCollateralType(CommitmentCollateralType _type)\n internal\n pure\n returns (CollateralType)\n {\n if (_type == CommitmentCollateralType.ERC20) {\n return CollateralType.ERC20;\n }\n if (\n _type == CommitmentCollateralType.ERC721 ||\n _type == CommitmentCollateralType.ERC721_ANY_ID ||\n _type == CommitmentCollateralType.ERC721_MERKLE_PROOF\n ) {\n return CollateralType.ERC721;\n }\n if (\n _type == CommitmentCollateralType.ERC1155 ||\n _type == CommitmentCollateralType.ERC1155_ANY_ID ||\n _type == CommitmentCollateralType.ERC1155_MERKLE_PROOF\n ) {\n return CollateralType.ERC1155;\n }\n\n revert(\"Unknown Collateral Type\");\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/LenderCommitmentForwarder_G2.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"../TellerV2MarketForwarder_G2.sol\";\n\n// Interfaces\nimport \"../interfaces/ICollateralManager.sol\";\nimport \"../interfaces/ILenderCommitmentForwarder.sol\";\nimport { Collateral, CollateralType } from \"../interfaces/escrow/ICollateralEscrowV1.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol\";\n\n// Libraries\nimport { MathUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol\";\n\ncontract LenderCommitmentForwarder_G2 is\n TellerV2MarketForwarder_G2,\n ILenderCommitmentForwarder\n{\n using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n\n // CommitmentId => commitment\n mapping(uint256 => Commitment) public commitments;\n\n uint256 commitmentCount;\n\n //https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/utils/structs/EnumerableSetUpgradeable.sol\n mapping(uint256 => EnumerableSetUpgradeable.AddressSet)\n internal commitmentBorrowersList;\n\n mapping(uint256 => uint256) public commitmentPrincipalAccepted;\n\n /**\n * @notice This event is emitted when a lender's commitment is created.\n * @param lender The address of the lender.\n * @param marketId The Id of the market the commitment applies to.\n * @param lendingToken The address of the asset being committed.\n * @param tokenAmount The amount of the asset being committed.\n */\n event CreatedCommitment(\n uint256 indexed commitmentId,\n address lender,\n uint256 marketId,\n address lendingToken,\n uint256 tokenAmount\n );\n\n /**\n * @notice This event is emitted when a lender's commitment is updated.\n * @param commitmentId The id of the commitment that was updated.\n * @param lender The address of the lender.\n * @param marketId The Id of the market the commitment applies to.\n * @param lendingToken The address of the asset being committed.\n * @param tokenAmount The amount of the asset being committed.\n */\n event UpdatedCommitment(\n uint256 indexed commitmentId,\n address lender,\n uint256 marketId,\n address lendingToken,\n uint256 tokenAmount\n );\n\n /**\n * @notice This event is emitted when the allowed borrowers for a commitment is updated.\n * @param commitmentId The id of the commitment that was updated.\n */\n event UpdatedCommitmentBorrowers(uint256 indexed commitmentId);\n\n /**\n * @notice This event is emitted when a lender's commitment has been deleted.\n * @param commitmentId The id of the commitment that was deleted.\n */\n event DeletedCommitment(uint256 indexed commitmentId);\n\n /**\n * @notice This event is emitted when a lender's commitment is exercised for a loan.\n * @param commitmentId The id of the commitment that was exercised.\n * @param borrower The address of the borrower.\n * @param tokenAmount The amount of the asset being committed.\n * @param bidId The bid id for the loan from TellerV2.\n */\n event ExercisedCommitment(\n uint256 indexed commitmentId,\n address borrower,\n uint256 tokenAmount,\n uint256 bidId\n );\n\n error InsufficientCommitmentAllocation(\n uint256 allocated,\n uint256 requested\n );\n error InsufficientBorrowerCollateral(uint256 required, uint256 actual);\n\n /** Modifiers **/\n\n modifier commitmentLender(uint256 _commitmentId) {\n require(\n commitments[_commitmentId].lender == _msgSender(),\n \"unauthorized commitment lender\"\n );\n _;\n }\n\n function validateCommitment(Commitment storage _commitment) internal {\n require(\n _commitment.expiration > uint32(block.timestamp),\n \"expired commitment\"\n );\n require(\n _commitment.maxPrincipal > 0,\n \"commitment principal allocation 0\"\n );\n\n if (_commitment.collateralTokenType != CommitmentCollateralType.NONE) {\n require(\n _commitment.maxPrincipalPerCollateralAmount > 0,\n \"commitment collateral ratio 0\"\n );\n\n if (\n _commitment.collateralTokenType ==\n CommitmentCollateralType.ERC20\n ) {\n require(\n _commitment.collateralTokenId == 0,\n \"commitment collateral token id must be 0 for ERC20\"\n );\n }\n }\n }\n\n /** External Functions **/\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address _protocolAddress, address _marketRegistry)\n TellerV2MarketForwarder_G2(_protocolAddress, _marketRegistry)\n {}\n\n /**\n * @notice Creates a loan commitment from a lender for a market.\n * @param _commitment The new commitment data expressed as a struct\n * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment\n * @return commitmentId_ returns the commitmentId for the created commitment\n */\n function createCommitment(\n Commitment calldata _commitment,\n address[] calldata _borrowerAddressList\n ) public returns (uint256 commitmentId_) {\n commitmentId_ = commitmentCount++;\n\n require(\n _commitment.lender == _msgSender(),\n \"unauthorized commitment creator\"\n );\n\n commitments[commitmentId_] = _commitment;\n\n //make sure the commitment data adheres to required specifications and limits\n validateCommitment(commitments[commitmentId_]);\n\n //the borrower allowlists is in a different storage space so we append them to the array with this method s\n _addBorrowersToCommitmentAllowlist(commitmentId_, _borrowerAddressList);\n\n emit CreatedCommitment(\n commitmentId_,\n _commitment.lender,\n _commitment.marketId,\n _commitment.principalTokenAddress,\n _commitment.maxPrincipal\n );\n }\n\n /**\n * @notice Updates the commitment of a lender to a market.\n * @param _commitmentId The Id of the commitment to update.\n * @param _commitment The new commitment data expressed as a struct\n */\n function updateCommitment(\n uint256 _commitmentId,\n Commitment calldata _commitment\n ) public commitmentLender(_commitmentId) {\n require(\n _commitment.lender == _msgSender(),\n \"Commitment lender cannot be updated.\"\n );\n\n require(\n _commitment.principalTokenAddress ==\n commitments[_commitmentId].principalTokenAddress,\n \"Principal token address cannot be updated.\"\n );\n require(\n _commitment.marketId == commitments[_commitmentId].marketId,\n \"Market Id cannot be updated.\"\n );\n\n commitments[_commitmentId] = _commitment;\n\n //make sure the commitment data still adheres to required specifications and limits\n validateCommitment(commitments[_commitmentId]);\n\n emit UpdatedCommitment(\n _commitmentId,\n _commitment.lender,\n _commitment.marketId,\n _commitment.principalTokenAddress,\n _commitment.maxPrincipal\n );\n }\n\n /**\n * @notice Updates the borrowers allowed to accept a commitment\n * @param _commitmentId The Id of the commitment to update.\n * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment\n */\n function addCommitmentBorrowers(\n uint256 _commitmentId,\n address[] calldata _borrowerAddressList\n ) public commitmentLender(_commitmentId) {\n _addBorrowersToCommitmentAllowlist(_commitmentId, _borrowerAddressList);\n }\n\n /**\n * @notice Updates the borrowers allowed to accept a commitment\n * @param _commitmentId The Id of the commitment to update.\n * @param _borrowerAddressList The array of borrowers that are allowed to accept loans using this commitment\n */\n function removeCommitmentBorrowers(\n uint256 _commitmentId,\n address[] calldata _borrowerAddressList\n ) public commitmentLender(_commitmentId) {\n _removeBorrowersFromCommitmentAllowlist(\n _commitmentId,\n _borrowerAddressList\n );\n }\n\n /**\n * @notice Adds a borrower to the allowlist for a commmitment.\n * @param _commitmentId The id of the commitment that will allow the new borrower\n * @param _borrowerArray the address array of the borrowers that will be allowed to accept loans using the commitment\n */\n function _addBorrowersToCommitmentAllowlist(\n uint256 _commitmentId,\n address[] calldata _borrowerArray\n ) internal {\n for (uint256 i = 0; i < _borrowerArray.length; i++) {\n commitmentBorrowersList[_commitmentId].add(_borrowerArray[i]);\n }\n emit UpdatedCommitmentBorrowers(_commitmentId);\n }\n\n /**\n * @notice Removes a borrower to the allowlist for a commmitment.\n * @param _commitmentId The id of the commitment that will allow the new borrower\n * @param _borrowerArray the address array of the borrowers that will be allowed to accept loans using the commitment\n */\n function _removeBorrowersFromCommitmentAllowlist(\n uint256 _commitmentId,\n address[] calldata _borrowerArray\n ) internal {\n for (uint256 i = 0; i < _borrowerArray.length; i++) {\n commitmentBorrowersList[_commitmentId].remove(_borrowerArray[i]);\n }\n emit UpdatedCommitmentBorrowers(_commitmentId);\n }\n\n /**\n * @notice Removes the commitment of a lender to a market.\n * @param _commitmentId The id of the commitment to delete.\n */\n function deleteCommitment(uint256 _commitmentId)\n public\n commitmentLender(_commitmentId)\n {\n delete commitments[_commitmentId];\n delete commitmentBorrowersList[_commitmentId];\n emit DeletedCommitment(_commitmentId);\n }\n\n /**\n * @notice Accept the commitment to submitBid and acceptBid using the funds\n * @dev LoanDuration must be longer than the market payment cycle\n * @param _commitmentId The id of the commitment being accepted.\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId of collateral to use for the loan if ERC721 or ERC1155.\n * @param _collateralTokenAddress The contract address to use for the loan collateral tokens.\n * @param _recipient The address to receive the loan funds.\n * @param _interestRate The interest rate APY to use for the loan in basis points.\n * @param _loanDuration The overall duration for the loan. Must be longer than market payment cycle duration.\n * @return bidId The ID of the loan that was created on TellerV2\n */\n function acceptCommitmentWithRecipient(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration\n ) public returns (uint256 bidId) {\n require(\n commitments[_commitmentId].collateralTokenType <=\n CommitmentCollateralType.ERC1155_ANY_ID,\n \"Invalid commitment collateral type\"\n );\n\n return\n _acceptCommitment(\n _commitmentId,\n _principalAmount,\n _collateralAmount,\n _collateralTokenId,\n _collateralTokenAddress,\n _recipient,\n _interestRate,\n _loanDuration\n );\n }\n\n function acceptCommitment(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n uint16 _interestRate,\n uint32 _loanDuration\n ) public returns (uint256 bidId) {\n return\n acceptCommitmentWithRecipient(\n _commitmentId,\n _principalAmount,\n _collateralAmount,\n _collateralTokenId,\n _collateralTokenAddress,\n address(0),\n _interestRate,\n _loanDuration\n );\n }\n\n /**\n * @notice Accept the commitment to submitBid and acceptBid using the funds\n * @dev LoanDuration must be longer than the market payment cycle\n * @param _commitmentId The id of the commitment being accepted.\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId of collateral to use for the loan if ERC721 or ERC1155.\n * @param _collateralTokenAddress The contract address to use for the loan collateral tokens.\n * @param _recipient The address to receive the loan funds.\n * @param _interestRate The interest rate APY to use for the loan in basis points.\n * @param _loanDuration The overall duration for the loan. Must be longer than market payment cycle duration.\n * @param _merkleProof An array of bytes32 which are the roots down the merkle tree, the merkle proof.\n * @return bidId The ID of the loan that was created on TellerV2\n */\n function acceptCommitmentWithRecipientAndProof(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration,\n bytes32[] calldata _merkleProof\n ) public returns (uint256 bidId) {\n require(\n commitments[_commitmentId].collateralTokenType ==\n CommitmentCollateralType.ERC721_MERKLE_PROOF ||\n commitments[_commitmentId].collateralTokenType ==\n CommitmentCollateralType.ERC1155_MERKLE_PROOF,\n \"Invalid commitment collateral type\"\n );\n\n bytes32 _merkleRoot = bytes32(\n commitments[_commitmentId].collateralTokenId\n );\n bytes32 _leaf = keccak256(abi.encodePacked(_collateralTokenId));\n\n //make sure collateral token id is a leaf within the proof\n require(\n MerkleProofUpgradeable.verifyCalldata(\n _merkleProof,\n _merkleRoot,\n _leaf\n ),\n \"Invalid proof\"\n );\n\n return\n _acceptCommitment(\n _commitmentId,\n _principalAmount,\n _collateralAmount,\n _collateralTokenId,\n _collateralTokenAddress,\n _recipient,\n _interestRate,\n _loanDuration\n );\n }\n\n function acceptCommitmentWithProof(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n uint16 _interestRate,\n uint32 _loanDuration,\n bytes32[] calldata _merkleProof\n ) public returns (uint256 bidId) {\n return\n acceptCommitmentWithRecipientAndProof(\n _commitmentId,\n _principalAmount,\n _collateralAmount,\n _collateralTokenId,\n _collateralTokenAddress,\n address(0),\n _interestRate,\n _loanDuration,\n _merkleProof\n );\n }\n\n /**\n * @notice Accept the commitment to submitBid and acceptBid using the funds\n * @dev LoanDuration must be longer than the market payment cycle\n * @param _commitmentId The id of the commitment being accepted.\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _collateralAmount The amount of collateral to use for the loan.\n * @param _collateralTokenId The tokenId of collateral to use for the loan if ERC721 or ERC1155.\n * @param _collateralTokenAddress The contract address to use for the loan collateral tokens.\n * @param _recipient The address to receive the loan funds.\n * @param _interestRate The interest rate APY to use for the loan in basis points.\n * @param _loanDuration The overall duration for the loan. Must be longer than market payment cycle duration.\n * @return bidId The ID of the loan that was created on TellerV2\n */\n function _acceptCommitment(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration\n ) internal returns (uint256 bidId) {\n Commitment storage commitment = commitments[_commitmentId];\n\n //make sure the commitment data adheres to required specifications and limits\n validateCommitment(commitment);\n\n //the collateral token of the commitment should be the same as the acceptor expects\n require(\n _collateralTokenAddress == commitment.collateralTokenAddress,\n \"Mismatching collateral token\"\n );\n //the interest rate must be at least as high has the commitment demands. The borrower can use a higher interest rate although that would not be beneficial to the borrower.\n require(\n _interestRate >= commitment.minInterestRate,\n \"Invalid interest rate\"\n );\n //the loan duration must be less than the commitment max loan duration. The lender who made the commitment expects the money to be returned before this window.\n require(\n _loanDuration <= commitment.maxDuration,\n \"Invalid loan max duration\"\n );\n\n require(\n commitmentPrincipalAccepted[bidId] <= commitment.maxPrincipal,\n \"Invalid loan max principal\"\n );\n\n require(\n commitmentBorrowersList[_commitmentId].length() == 0 ||\n commitmentBorrowersList[_commitmentId].contains(_msgSender()),\n \"unauthorized commitment borrower\"\n );\n //require that the borrower accepting the commitment cannot borrow more than the commitments max principal\n if (_principalAmount > commitment.maxPrincipal) {\n revert InsufficientCommitmentAllocation({\n allocated: commitment.maxPrincipal,\n requested: _principalAmount\n });\n }\n\n uint256 requiredCollateral = getRequiredCollateral(\n _principalAmount,\n commitment.maxPrincipalPerCollateralAmount,\n commitment.collateralTokenType,\n commitment.collateralTokenAddress,\n commitment.principalTokenAddress\n );\n\n if (_collateralAmount < requiredCollateral) {\n revert InsufficientBorrowerCollateral({\n required: requiredCollateral,\n actual: _collateralAmount\n });\n }\n\n //ERC721 assets must have a quantity of 1\n if (\n commitment.collateralTokenType == CommitmentCollateralType.ERC721 ||\n commitment.collateralTokenType ==\n CommitmentCollateralType.ERC721_ANY_ID ||\n commitment.collateralTokenType ==\n CommitmentCollateralType.ERC721_MERKLE_PROOF\n ) {\n require(\n _collateralAmount == 1,\n \"invalid commitment collateral amount for ERC721\"\n );\n }\n\n //ERC721 and ERC1155 types strictly enforce a specific token Id. ERC721_ANY and ERC1155_ANY do not.\n if (\n commitment.collateralTokenType == CommitmentCollateralType.ERC721 ||\n commitment.collateralTokenType == CommitmentCollateralType.ERC1155\n ) {\n require(\n commitment.collateralTokenId == _collateralTokenId,\n \"invalid commitment collateral tokenId\"\n );\n }\n\n commitmentPrincipalAccepted[_commitmentId] += _principalAmount;\n\n require(\n commitmentPrincipalAccepted[_commitmentId] <=\n commitment.maxPrincipal,\n \"Exceeds max principal of commitment\"\n );\n\n CreateLoanArgs memory createLoanArgs;\n createLoanArgs.marketId = commitment.marketId;\n createLoanArgs.lendingToken = commitment.principalTokenAddress;\n createLoanArgs.principal = _principalAmount;\n createLoanArgs.duration = _loanDuration;\n createLoanArgs.interestRate = _interestRate;\n createLoanArgs.recipient = _recipient;\n if (commitment.collateralTokenType != CommitmentCollateralType.NONE) {\n createLoanArgs.collateral = new Collateral[](1);\n createLoanArgs.collateral[0] = Collateral({\n _collateralType: _getEscrowCollateralType(\n commitment.collateralTokenType\n ),\n _tokenId: _collateralTokenId,\n _amount: _collateralAmount,\n _collateralAddress: commitment.collateralTokenAddress\n });\n }\n\n bidId = _submitBidWithCollateral(createLoanArgs, _msgSender());\n\n _acceptBid(bidId, commitment.lender);\n\n emit ExercisedCommitment(\n _commitmentId,\n _msgSender(),\n _principalAmount,\n bidId\n );\n }\n\n /**\n * @notice Calculate the amount of collateral required to borrow a loan with _principalAmount of principal\n * @param _principalAmount The amount of currency to borrow for the loan.\n * @param _maxPrincipalPerCollateralAmount The ratio for the amount of principal that can be borrowed for each amount of collateral. This is expanded additionally by the principal decimals.\n * @param _collateralTokenType The type of collateral for the loan either ERC20, ERC721, ERC1155, or None.\n * @param _collateralTokenAddress The contract address for the collateral for the loan.\n * @param _principalTokenAddress The contract address for the principal for the loan.\n */\n function getRequiredCollateral(\n uint256 _principalAmount,\n uint256 _maxPrincipalPerCollateralAmount,\n CommitmentCollateralType _collateralTokenType,\n address _collateralTokenAddress,\n address _principalTokenAddress\n ) public view virtual returns (uint256) {\n if (_collateralTokenType == CommitmentCollateralType.NONE) {\n return 0;\n }\n\n uint8 collateralDecimals;\n uint8 principalDecimals = IERC20MetadataUpgradeable(\n _principalTokenAddress\n ).decimals();\n\n if (_collateralTokenType == CommitmentCollateralType.ERC20) {\n collateralDecimals = IERC20MetadataUpgradeable(\n _collateralTokenAddress\n ).decimals();\n }\n\n /*\n * The principalAmount is expanded by (collateralDecimals+principalDecimals) to increase precision\n * and then it is divided by _maxPrincipalPerCollateralAmount which should already been expanded by principalDecimals\n */\n return\n MathUpgradeable.mulDiv(\n _principalAmount,\n (10**(collateralDecimals + principalDecimals)),\n _maxPrincipalPerCollateralAmount,\n MathUpgradeable.Rounding.Up\n );\n }\n\n /**\n * @notice Return the array of borrowers that are allowlisted for a commitment\n * @param _commitmentId The commitment id for the commitment to query.\n * @return borrowers_ An array of addresses restricted to accept the commitment. Empty array means unrestricted.\n */\n function getCommitmentBorrowers(uint256 _commitmentId)\n external\n view\n returns (address[] memory borrowers_)\n {\n borrowers_ = commitmentBorrowersList[_commitmentId].values();\n }\n\n /**\n * @notice Return the collateral type based on the commitmentcollateral type. Collateral type is used in the base lending protocol.\n * @param _type The type of collateral to be used for the loan.\n */\n function _getEscrowCollateralType(CommitmentCollateralType _type)\n internal\n pure\n returns (CollateralType)\n {\n if (_type == CommitmentCollateralType.ERC20) {\n return CollateralType.ERC20;\n }\n if (\n _type == CommitmentCollateralType.ERC721 ||\n _type == CommitmentCollateralType.ERC721_ANY_ID ||\n _type == CommitmentCollateralType.ERC721_MERKLE_PROOF\n ) {\n return CollateralType.ERC721;\n }\n if (\n _type == CommitmentCollateralType.ERC1155 ||\n _type == CommitmentCollateralType.ERC1155_ANY_ID ||\n _type == CommitmentCollateralType.ERC1155_MERKLE_PROOF\n ) {\n return CollateralType.ERC1155;\n }\n\n revert(\"Unknown Collateral Type\");\n }\n\n function getCommitmentMarketId(uint256 _commitmentId)\n external\n view\n returns (uint256)\n {\n return commitments[_commitmentId].marketId;\n }\n\n function getCommitmentLender(uint256 _commitmentId)\n external\n view\n returns (address)\n {\n return commitments[_commitmentId].lender;\n }\n\n function getCommitmentAcceptedPrincipal(uint256 _commitmentId)\n external\n view\n returns (uint256)\n {\n return commitmentPrincipalAccepted[_commitmentId];\n }\n\n function getCommitmentMaxPrincipal(uint256 _commitmentId)\n external\n view\n returns (uint256)\n {\n return commitments[_commitmentId].maxPrincipal;\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/LenderCommitmentForwarder_G3.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"./LenderCommitmentForwarder_G2.sol\";\nimport \"./extensions/ExtensionsContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\ncontract LenderCommitmentForwarder_G3 is\n LenderCommitmentForwarder_G2,\n ExtensionsContextUpgradeable\n{\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address _tellerV2, address _marketRegistry)\n LenderCommitmentForwarder_G2(_tellerV2, _marketRegistry)\n {}\n\n function _msgSender()\n internal\n view\n virtual\n override(ContextUpgradeable, ExtensionsContextUpgradeable)\n returns (address sender)\n {\n return ExtensionsContextUpgradeable._msgSender();\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/LenderCommitmentForwarder.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"../interfaces/ILenderCommitmentForwarder.sol\";\nimport \"./LenderCommitmentForwarder_G1.sol\";\n\ncontract LenderCommitmentForwarder is LenderCommitmentForwarder_G1 {\n constructor(address _tellerV2, address _marketRegistry)\n LenderCommitmentForwarder_G1(_tellerV2, _marketRegistry)\n {\n _disableInitializers();\n }\n}\n" + }, + "contracts/LenderCommitmentForwarder/LenderCommitmentForwarderStaging.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"../interfaces/ILenderCommitmentForwarder.sol\";\nimport \"./LenderCommitmentForwarder_G3.sol\";\n\ncontract LenderCommitmentForwarderStaging is\n ILenderCommitmentForwarder,\n LenderCommitmentForwarder_G3\n{\n constructor(address _tellerV2, address _marketRegistry)\n LenderCommitmentForwarder_G3(_tellerV2, _marketRegistry)\n {\n // we only want this on an proxy deployment so it only affects the impl\n _disableInitializers();\n }\n}\n" + }, + "contracts/LenderManager.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol\";\n\n// Interfaces\nimport \"./interfaces/ILenderManager.sol\";\nimport \"./interfaces/ITellerV2.sol\";\nimport \"./interfaces/IMarketRegistry.sol\";\n\ncontract LenderManager is\n Initializable,\n OwnableUpgradeable,\n ERC721Upgradeable,\n ILenderManager\n{\n IMarketRegistry public immutable marketRegistry;\n\n constructor(IMarketRegistry _marketRegistry) {\n marketRegistry = _marketRegistry;\n }\n\n function initialize() external initializer {\n __LenderManager_init();\n }\n\n function __LenderManager_init() internal onlyInitializing {\n __Ownable_init();\n __ERC721_init(\"TellerLoan\", \"TLN\");\n }\n\n /**\n * @notice Registers a new active lender for a loan, minting the nft\n * @param _bidId The id for the loan to set.\n * @param _newLender The address of the new active lender.\n */\n function registerLoan(uint256 _bidId, address _newLender)\n public\n override\n onlyOwner\n {\n _safeMint(_newLender, _bidId, \"\");\n }\n\n /**\n * @notice Returns the address of the lender that owns a given loan/bid.\n * @param _bidId The id of the bid of which to return the market id\n */\n function _getLoanMarketId(uint256 _bidId) internal view returns (uint256) {\n return ITellerV2(owner()).getLoanMarketId(_bidId);\n }\n\n /**\n * @notice Returns the verification status of a lender for a market.\n * @param _lender The address of the lender which should be verified by the market\n * @param _bidId The id of the bid of which to return the market id\n */\n function _hasMarketVerification(address _lender, uint256 _bidId)\n internal\n view\n virtual\n returns (bool isVerified_)\n {\n uint256 _marketId = _getLoanMarketId(_bidId);\n\n (isVerified_, ) = marketRegistry.isVerifiedLender(_marketId, _lender);\n }\n\n /** ERC721 Functions **/\n\n function _beforeTokenTransfer(address, address to, uint256 tokenId, uint256)\n internal\n override\n {\n require(_hasMarketVerification(to, tokenId), \"Not approved by market\");\n }\n\n function _baseURI() internal view override returns (string memory) {\n return \"\";\n }\n}\n" + }, + "contracts/libraries/DateTimeLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0 <0.9.0;\n\n// ----------------------------------------------------------------------------\n// BokkyPooBah's DateTime Library v1.01\n//\n// A gas-efficient Solidity date and time library\n//\n// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary\n//\n// Tested date range 1970/01/01 to 2345/12/31\n//\n// Conventions:\n// Unit | Range | Notes\n// :-------- |:-------------:|:-----\n// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC\n// year | 1970 ... 2345 |\n// month | 1 ... 12 |\n// day | 1 ... 31 |\n// hour | 0 ... 23 |\n// minute | 0 ... 59 |\n// second | 0 ... 59 |\n// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday\n//\n//\n// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.\n// ----------------------------------------------------------------------------\n\nlibrary BokkyPooBahsDateTimeLibrary {\n uint constant SECONDS_PER_DAY = 24 * 60 * 60;\n uint constant SECONDS_PER_HOUR = 60 * 60;\n uint constant SECONDS_PER_MINUTE = 60;\n int constant OFFSET19700101 = 2440588;\n\n uint constant DOW_MON = 1;\n uint constant DOW_TUE = 2;\n uint constant DOW_WED = 3;\n uint constant DOW_THU = 4;\n uint constant DOW_FRI = 5;\n uint constant DOW_SAT = 6;\n uint constant DOW_SUN = 7;\n\n // ------------------------------------------------------------------------\n // Calculate the number of days from 1970/01/01 to year/month/day using\n // the date conversion algorithm from\n // https://aa.usno.navy.mil/faq/JD_formula.html\n // and subtracting the offset 2440588 so that 1970/01/01 is day 0\n //\n // days = day\n // - 32075\n // + 1461 * (year + 4800 + (month - 14) / 12) / 4\n // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12\n // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4\n // - offset\n // ------------------------------------------------------------------------\n function _daysFromDate(uint year, uint month, uint day)\n internal\n pure\n returns (uint _days)\n {\n require(year >= 1970);\n int _year = int(year);\n int _month = int(month);\n int _day = int(day);\n\n int __days = _day -\n 32075 +\n (1461 * (_year + 4800 + (_month - 14) / 12)) /\n 4 +\n (367 * (_month - 2 - ((_month - 14) / 12) * 12)) /\n 12 -\n (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) /\n 4 -\n OFFSET19700101;\n\n _days = uint(__days);\n }\n\n // ------------------------------------------------------------------------\n // Calculate year/month/day from the number of days since 1970/01/01 using\n // the date conversion algorithm from\n // http://aa.usno.navy.mil/faq/docs/JD_Formula.php\n // and adding the offset 2440588 so that 1970/01/01 is day 0\n //\n // int L = days + 68569 + offset\n // int N = 4 * L / 146097\n // L = L - (146097 * N + 3) / 4\n // year = 4000 * (L + 1) / 1461001\n // L = L - 1461 * year / 4 + 31\n // month = 80 * L / 2447\n // dd = L - 2447 * month / 80\n // L = month / 11\n // month = month + 2 - 12 * L\n // year = 100 * (N - 49) + year + L\n // ------------------------------------------------------------------------\n function _daysToDate(uint _days)\n internal\n pure\n returns (uint year, uint month, uint day)\n {\n int __days = int(_days);\n\n int L = __days + 68569 + OFFSET19700101;\n int N = (4 * L) / 146097;\n L = L - (146097 * N + 3) / 4;\n int _year = (4000 * (L + 1)) / 1461001;\n L = L - (1461 * _year) / 4 + 31;\n int _month = (80 * L) / 2447;\n int _day = L - (2447 * _month) / 80;\n L = _month / 11;\n _month = _month + 2 - 12 * L;\n _year = 100 * (N - 49) + _year + L;\n\n year = uint(_year);\n month = uint(_month);\n day = uint(_day);\n }\n\n function timestampFromDate(uint year, uint month, uint day)\n internal\n pure\n returns (uint timestamp)\n {\n timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;\n }\n\n function timestampFromDateTime(\n uint year,\n uint month,\n uint day,\n uint hour,\n uint minute,\n uint second\n ) internal pure returns (uint timestamp) {\n timestamp =\n _daysFromDate(year, month, day) *\n SECONDS_PER_DAY +\n hour *\n SECONDS_PER_HOUR +\n minute *\n SECONDS_PER_MINUTE +\n second;\n }\n\n function timestampToDate(uint timestamp)\n internal\n pure\n returns (uint year, uint month, uint day)\n {\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n\n function timestampToDateTime(uint timestamp)\n internal\n pure\n returns (\n uint year,\n uint month,\n uint day,\n uint hour,\n uint minute,\n uint second\n )\n {\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n uint secs = timestamp % SECONDS_PER_DAY;\n hour = secs / SECONDS_PER_HOUR;\n secs = secs % SECONDS_PER_HOUR;\n minute = secs / SECONDS_PER_MINUTE;\n second = secs % SECONDS_PER_MINUTE;\n }\n\n function isValidDate(uint year, uint month, uint day)\n internal\n pure\n returns (bool valid)\n {\n if (year >= 1970 && month > 0 && month <= 12) {\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day > 0 && day <= daysInMonth) {\n valid = true;\n }\n }\n }\n\n function isValidDateTime(\n uint year,\n uint month,\n uint day,\n uint hour,\n uint minute,\n uint second\n ) internal pure returns (bool valid) {\n if (isValidDate(year, month, day)) {\n if (hour < 24 && minute < 60 && second < 60) {\n valid = true;\n }\n }\n }\n\n function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {\n (uint year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);\n leapYear = _isLeapYear(year);\n }\n\n function _isLeapYear(uint year) internal pure returns (bool leapYear) {\n leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);\n }\n\n function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {\n weekDay = getDayOfWeek(timestamp) <= DOW_FRI;\n }\n\n function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {\n weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;\n }\n\n function getDaysInMonth(uint timestamp)\n internal\n pure\n returns (uint daysInMonth)\n {\n (uint year, uint month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);\n daysInMonth = _getDaysInMonth(year, month);\n }\n\n function _getDaysInMonth(uint year, uint month)\n internal\n pure\n returns (uint daysInMonth)\n {\n if (\n month == 1 ||\n month == 3 ||\n month == 5 ||\n month == 7 ||\n month == 8 ||\n month == 10 ||\n month == 12\n ) {\n daysInMonth = 31;\n } else if (month != 2) {\n daysInMonth = 30;\n } else {\n daysInMonth = _isLeapYear(year) ? 29 : 28;\n }\n }\n\n // 1 = Monday, 7 = Sunday\n function getDayOfWeek(uint timestamp)\n internal\n pure\n returns (uint dayOfWeek)\n {\n uint _days = timestamp / SECONDS_PER_DAY;\n dayOfWeek = ((_days + 3) % 7) + 1;\n }\n\n function getYear(uint timestamp) internal pure returns (uint year) {\n (year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n\n function getMonth(uint timestamp) internal pure returns (uint month) {\n (, month, ) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n\n function getDay(uint timestamp) internal pure returns (uint day) {\n (, , day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n\n function getHour(uint timestamp) internal pure returns (uint hour) {\n uint secs = timestamp % SECONDS_PER_DAY;\n hour = secs / SECONDS_PER_HOUR;\n }\n\n function getMinute(uint timestamp) internal pure returns (uint minute) {\n uint secs = timestamp % SECONDS_PER_HOUR;\n minute = secs / SECONDS_PER_MINUTE;\n }\n\n function getSecond(uint timestamp) internal pure returns (uint second) {\n second = timestamp % SECONDS_PER_MINUTE;\n }\n\n function addYears(uint timestamp, uint _years)\n internal\n pure\n returns (uint newTimestamp)\n {\n (uint year, uint month, uint day) = _daysToDate(\n timestamp / SECONDS_PER_DAY\n );\n year += _years;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day > daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp =\n _daysFromDate(year, month, day) *\n SECONDS_PER_DAY +\n (timestamp % SECONDS_PER_DAY);\n require(newTimestamp >= timestamp);\n }\n\n function addMonths(uint timestamp, uint _months)\n internal\n pure\n returns (uint newTimestamp)\n {\n (uint year, uint month, uint day) = _daysToDate(\n timestamp / SECONDS_PER_DAY\n );\n month += _months;\n year += (month - 1) / 12;\n month = ((month - 1) % 12) + 1;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day > daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp =\n _daysFromDate(year, month, day) *\n SECONDS_PER_DAY +\n (timestamp % SECONDS_PER_DAY);\n require(newTimestamp >= timestamp);\n }\n\n function addDays(uint timestamp, uint _days)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp + _days * SECONDS_PER_DAY;\n require(newTimestamp >= timestamp);\n }\n\n function addHours(uint timestamp, uint _hours)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;\n require(newTimestamp >= timestamp);\n }\n\n function addMinutes(uint timestamp, uint _minutes)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;\n require(newTimestamp >= timestamp);\n }\n\n function addSeconds(uint timestamp, uint _seconds)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp + _seconds;\n require(newTimestamp >= timestamp);\n }\n\n function subYears(uint timestamp, uint _years)\n internal\n pure\n returns (uint newTimestamp)\n {\n (uint year, uint month, uint day) = _daysToDate(\n timestamp / SECONDS_PER_DAY\n );\n year -= _years;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day > daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp =\n _daysFromDate(year, month, day) *\n SECONDS_PER_DAY +\n (timestamp % SECONDS_PER_DAY);\n require(newTimestamp <= timestamp);\n }\n\n function subMonths(uint timestamp, uint _months)\n internal\n pure\n returns (uint newTimestamp)\n {\n (uint year, uint month, uint day) = _daysToDate(\n timestamp / SECONDS_PER_DAY\n );\n uint yearMonth = year * 12 + (month - 1) - _months;\n year = yearMonth / 12;\n month = (yearMonth % 12) + 1;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day > daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp =\n _daysFromDate(year, month, day) *\n SECONDS_PER_DAY +\n (timestamp % SECONDS_PER_DAY);\n require(newTimestamp <= timestamp);\n }\n\n function subDays(uint timestamp, uint _days)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp - _days * SECONDS_PER_DAY;\n require(newTimestamp <= timestamp);\n }\n\n function subHours(uint timestamp, uint _hours)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;\n require(newTimestamp <= timestamp);\n }\n\n function subMinutes(uint timestamp, uint _minutes)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;\n require(newTimestamp <= timestamp);\n }\n\n function subSeconds(uint timestamp, uint _seconds)\n internal\n pure\n returns (uint newTimestamp)\n {\n newTimestamp = timestamp - _seconds;\n require(newTimestamp <= timestamp);\n }\n\n function diffYears(uint fromTimestamp, uint toTimestamp)\n internal\n pure\n returns (uint _years)\n {\n require(fromTimestamp <= toTimestamp);\n (uint fromYear, , ) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);\n (uint toYear, , ) = _daysToDate(toTimestamp / SECONDS_PER_DAY);\n _years = toYear - fromYear;\n }\n\n function diffMonths(uint fromTimestamp, uint toTimestamp)\n internal\n pure\n returns (uint _months)\n {\n require(fromTimestamp <= toTimestamp);\n (uint fromYear, uint fromMonth, ) = _daysToDate(\n fromTimestamp / SECONDS_PER_DAY\n );\n (uint toYear, uint toMonth, ) = _daysToDate(\n toTimestamp / SECONDS_PER_DAY\n );\n _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;\n }\n\n function diffDays(uint fromTimestamp, uint toTimestamp)\n internal\n pure\n returns (uint _days)\n {\n require(fromTimestamp <= toTimestamp);\n _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;\n }\n\n function diffHours(uint fromTimestamp, uint toTimestamp)\n internal\n pure\n returns (uint _hours)\n {\n require(fromTimestamp <= toTimestamp);\n _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;\n }\n\n function diffMinutes(uint fromTimestamp, uint toTimestamp)\n internal\n pure\n returns (uint _minutes)\n {\n require(fromTimestamp <= toTimestamp);\n _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;\n }\n\n function diffSeconds(uint fromTimestamp, uint toTimestamp)\n internal\n pure\n returns (uint _seconds)\n {\n require(fromTimestamp <= toTimestamp);\n _seconds = toTimestamp - fromTimestamp;\n }\n}\n" + }, + "contracts/libraries/NumbersLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Libraries\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"./WadRayMath.sol\";\n\n/**\n * @dev Utility library for uint256 numbers\n *\n * @author develop@teller.finance\n */\nlibrary NumbersLib {\n using WadRayMath for uint256;\n\n /**\n * @dev It represents 100% with 2 decimal places.\n */\n uint16 internal constant PCT_100 = 10000;\n\n function percentFactor(uint256 decimals) internal pure returns (uint256) {\n return 100 * (10**decimals);\n }\n\n /**\n * @notice Returns a percentage value of a number.\n * @param self The number to get a percentage of.\n * @param percentage The percentage value to calculate with 2 decimal places (10000 = 100%).\n */\n function percent(uint256 self, uint16 percentage)\n internal\n pure\n returns (uint256)\n {\n return percent(self, percentage, 2);\n }\n\n /**\n * @notice Returns a percentage value of a number.\n * @param self The number to get a percentage of.\n * @param percentage The percentage value to calculate with.\n * @param decimals The number of decimals the percentage value is in.\n */\n function percent(uint256 self, uint256 percentage, uint256 decimals)\n internal\n pure\n returns (uint256)\n {\n return (self * percentage) / percentFactor(decimals);\n }\n\n /**\n * @notice it returns the absolute number of a specified parameter\n * @param self the number to be returned in it's absolute\n * @return the absolute number\n */\n function abs(int256 self) internal pure returns (uint256) {\n return self >= 0 ? uint256(self) : uint256(-1 * self);\n }\n\n /**\n * @notice Returns a ratio percentage of {num1} to {num2}.\n * @dev Returned value is type uint16.\n * @param num1 The number used to get the ratio for.\n * @param num2 The number used to get the ratio from.\n * @return Ratio percentage with 2 decimal places (10000 = 100%).\n */\n function ratioOf(uint256 num1, uint256 num2)\n internal\n pure\n returns (uint16)\n {\n return SafeCast.toUint16(ratioOf(num1, num2, 2));\n }\n\n /**\n * @notice Returns a ratio percentage of {num1} to {num2}.\n * @param num1 The number used to get the ratio for.\n * @param num2 The number used to get the ratio from.\n * @param decimals The number of decimals the percentage value is returned in.\n * @return Ratio percentage value.\n */\n function ratioOf(uint256 num1, uint256 num2, uint256 decimals)\n internal\n pure\n returns (uint256)\n {\n if (num2 == 0) return 0;\n return (num1 * percentFactor(decimals)) / num2;\n }\n\n /**\n * @notice Calculates the payment amount for a cycle duration.\n * The formula is calculated based on the standard Estimated Monthly Installment (https://en.wikipedia.org/wiki/Equated_monthly_installment)\n * EMI = [P x R x (1+R)^N]/[(1+R)^N-1]\n * @param principal The starting amount that is owed on the loan.\n * @param loanDuration The length of the loan.\n * @param cycleDuration The length of the loan's payment cycle.\n * @param apr The annual percentage rate of the loan.\n */\n function pmt(\n uint256 principal,\n uint32 loanDuration,\n uint32 cycleDuration,\n uint16 apr,\n uint256 daysInYear\n ) internal pure returns (uint256) {\n require(\n loanDuration >= cycleDuration,\n \"PMT: cycle duration < loan duration\"\n );\n if (apr == 0)\n return\n Math.mulDiv(\n principal,\n cycleDuration,\n loanDuration,\n Math.Rounding.Up\n );\n\n // Number of payment cycles for the duration of the loan\n uint256 n = Math.ceilDiv(loanDuration, cycleDuration);\n\n uint256 one = WadRayMath.wad();\n uint256 r = WadRayMath.pctToWad(apr).wadMul(cycleDuration).wadDiv(\n daysInYear\n );\n uint256 exp = (one + r).wadPow(n);\n uint256 numerator = principal.wadMul(r).wadMul(exp);\n uint256 denominator = exp - one;\n\n return numerator.wadDiv(denominator);\n }\n}\n" + }, + "contracts/libraries/V2Calculations.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n\n// SPDX-License-Identifier: MIT\n\n// Libraries\nimport \"./NumbersLib.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { Bid } from \"../TellerV2Storage.sol\";\nimport { BokkyPooBahsDateTimeLibrary as BPBDTL } from \"./DateTimeLib.sol\";\n\nenum PaymentType {\n EMI,\n Bullet\n}\n\nenum PaymentCycleType {\n Seconds,\n Monthly\n}\n\nlibrary V2Calculations {\n using NumbersLib for uint256;\n\n /**\n * @notice Returns the timestamp of the last payment made for a loan.\n * @param _bid The loan bid struct to get the timestamp for.\n */\n function lastRepaidTimestamp(Bid storage _bid)\n internal\n view\n returns (uint32)\n {\n return\n _bid.loanDetails.lastRepaidTimestamp == 0\n ? _bid.loanDetails.acceptedTimestamp\n : _bid.loanDetails.lastRepaidTimestamp;\n }\n\n /**\n * @notice Calculates the amount owed for a loan.\n * @param _bid The loan bid struct to get the owed amount for.\n * @param _timestamp The timestamp at which to get the owed amount at.\n * @param _paymentCycleType The payment cycle type of the loan (Seconds or Monthly).\n */\n function calculateAmountOwed(\n Bid storage _bid,\n uint256 _timestamp,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentCycleDuration\n )\n internal\n view\n returns (\n uint256 owedPrincipal_,\n uint256 duePrincipal_,\n uint256 interest_\n )\n {\n // Total principal left to pay\n return\n calculateAmountOwed(\n _bid,\n lastRepaidTimestamp(_bid),\n _timestamp,\n _paymentCycleType,\n _paymentCycleDuration\n );\n }\n\n function calculateAmountOwed(\n Bid storage _bid,\n uint256 _lastRepaidTimestamp,\n uint256 _timestamp,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentCycleDuration\n )\n internal\n view\n returns (\n uint256 owedPrincipal_,\n uint256 duePrincipal_,\n uint256 interest_\n )\n {\n owedPrincipal_ =\n _bid.loanDetails.principal -\n _bid.loanDetails.totalRepaid.principal;\n\n uint256 daysInYear = _paymentCycleType == PaymentCycleType.Monthly\n ? 360 days\n : 365 days;\n\n uint256 interestOwedInAYear = owedPrincipal_.percent(_bid.terms.APR);\n uint256 owedTime = _timestamp - uint256(_lastRepaidTimestamp);\n interest_ = (interestOwedInAYear * owedTime) / daysInYear;\n\n bool isLastPaymentCycle;\n {\n uint256 lastPaymentCycleDuration = _bid.loanDetails.loanDuration %\n _paymentCycleDuration;\n if (lastPaymentCycleDuration == 0) {\n lastPaymentCycleDuration = _paymentCycleDuration;\n }\n\n uint256 endDate = uint256(_bid.loanDetails.acceptedTimestamp) +\n uint256(_bid.loanDetails.loanDuration);\n uint256 lastPaymentCycleStart = endDate -\n uint256(lastPaymentCycleDuration);\n\n isLastPaymentCycle =\n uint256(_timestamp) > lastPaymentCycleStart ||\n owedPrincipal_ + interest_ <= _bid.terms.paymentCycleAmount;\n }\n\n if (_bid.paymentType == PaymentType.Bullet) {\n if (isLastPaymentCycle) {\n duePrincipal_ = owedPrincipal_;\n }\n } else {\n // Default to PaymentType.EMI\n // Max payable amount in a cycle\n // NOTE: the last cycle could have less than the calculated payment amount\n\n uint256 owedAmount = isLastPaymentCycle\n ? owedPrincipal_ + interest_\n : (_bid.terms.paymentCycleAmount * owedTime) /\n _paymentCycleDuration;\n\n duePrincipal_ = Math.min(owedAmount - interest_, owedPrincipal_);\n }\n }\n\n /**\n * @notice Calculates the amount owed for a loan for the next payment cycle.\n * @param _type The payment type of the loan.\n * @param _cycleType The cycle type set for the loan. (Seconds or Monthly)\n * @param _principal The starting amount that is owed on the loan.\n * @param _duration The length of the loan.\n * @param _paymentCycle The length of the loan's payment cycle.\n * @param _apr The annual percentage rate of the loan.\n */\n function calculatePaymentCycleAmount(\n PaymentType _type,\n PaymentCycleType _cycleType,\n uint256 _principal,\n uint32 _duration,\n uint32 _paymentCycle,\n uint16 _apr\n ) internal returns (uint256) {\n uint256 daysInYear = _cycleType == PaymentCycleType.Monthly\n ? 360 days\n : 365 days;\n if (_type == PaymentType.Bullet) {\n return\n _principal.percent(_apr).percent(\n uint256(_paymentCycle).ratioOf(daysInYear, 10),\n 10\n );\n }\n // Default to PaymentType.EMI\n return\n NumbersLib.pmt(\n _principal,\n _duration,\n _paymentCycle,\n _apr,\n daysInYear\n );\n }\n\n function calculateNextDueDate(\n uint32 _acceptedTimestamp,\n uint32 _paymentCycle,\n uint32 _loanDuration,\n uint32 _lastRepaidTimestamp,\n PaymentCycleType _bidPaymentCycleType\n ) public view returns (uint32 dueDate_) {\n // Calculate due date if payment cycle is set to monthly\n if (_bidPaymentCycleType == PaymentCycleType.Monthly) {\n // Calculate the cycle number the last repayment was made\n uint256 lastPaymentCycle = BPBDTL.diffMonths(\n _acceptedTimestamp,\n _lastRepaidTimestamp\n );\n if (\n BPBDTL.getDay(_lastRepaidTimestamp) >\n BPBDTL.getDay(_acceptedTimestamp)\n ) {\n lastPaymentCycle += 2;\n } else {\n lastPaymentCycle += 1;\n }\n\n dueDate_ = uint32(\n BPBDTL.addMonths(_acceptedTimestamp, lastPaymentCycle)\n );\n } else if (_bidPaymentCycleType == PaymentCycleType.Seconds) {\n // Start with the original due date being 1 payment cycle since bid was accepted\n dueDate_ = _acceptedTimestamp + _paymentCycle;\n // Calculate the cycle number the last repayment was made\n uint32 delta = _lastRepaidTimestamp - _acceptedTimestamp;\n if (delta > 0) {\n uint32 repaymentCycle = uint32(\n Math.ceilDiv(delta, _paymentCycle)\n );\n dueDate_ += (repaymentCycle * _paymentCycle);\n }\n }\n\n uint32 endOfLoan = _acceptedTimestamp + _loanDuration;\n //if we are in the last payment cycle, the next due date is the end of loan duration\n if (dueDate_ > endOfLoan) {\n dueDate_ = endOfLoan;\n }\n }\n}\n" + }, + "contracts/libraries/WadRayMath.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\n\n/**\n * @title WadRayMath library\n * @author Multiplier Finance\n * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)\n */\nlibrary WadRayMath {\n using SafeMath for uint256;\n\n uint256 internal constant WAD = 1e18;\n uint256 internal constant halfWAD = WAD / 2;\n\n uint256 internal constant RAY = 1e27;\n uint256 internal constant halfRAY = RAY / 2;\n\n uint256 internal constant WAD_RAY_RATIO = 1e9;\n uint256 internal constant PCT_WAD_RATIO = 1e14;\n uint256 internal constant PCT_RAY_RATIO = 1e23;\n\n function ray() internal pure returns (uint256) {\n return RAY;\n }\n\n function wad() internal pure returns (uint256) {\n return WAD;\n }\n\n function halfRay() internal pure returns (uint256) {\n return halfRAY;\n }\n\n function halfWad() internal pure returns (uint256) {\n return halfWAD;\n }\n\n function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {\n return halfWAD.add(a.mul(b)).div(WAD);\n }\n\n function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 halfB = b / 2;\n\n return halfB.add(a.mul(WAD)).div(b);\n }\n\n function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {\n return halfRAY.add(a.mul(b)).div(RAY);\n }\n\n function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 halfB = b / 2;\n\n return halfB.add(a.mul(RAY)).div(b);\n }\n\n function rayToWad(uint256 a) internal pure returns (uint256) {\n uint256 halfRatio = WAD_RAY_RATIO / 2;\n\n return halfRatio.add(a).div(WAD_RAY_RATIO);\n }\n\n function rayToPct(uint256 a) internal pure returns (uint16) {\n uint256 halfRatio = PCT_RAY_RATIO / 2;\n\n uint256 val = halfRatio.add(a).div(PCT_RAY_RATIO);\n return SafeCast.toUint16(val);\n }\n\n function wadToPct(uint256 a) internal pure returns (uint16) {\n uint256 halfRatio = PCT_WAD_RATIO / 2;\n\n uint256 val = halfRatio.add(a).div(PCT_WAD_RATIO);\n return SafeCast.toUint16(val);\n }\n\n function wadToRay(uint256 a) internal pure returns (uint256) {\n return a.mul(WAD_RAY_RATIO);\n }\n\n function pctToRay(uint16 a) internal pure returns (uint256) {\n return uint256(a).mul(RAY).div(1e4);\n }\n\n function pctToWad(uint16 a) internal pure returns (uint256) {\n return uint256(a).mul(WAD).div(1e4);\n }\n\n /**\n * @dev calculates base^duration. The code uses the ModExp precompile\n * @return z base^duration, in ray\n */\n function rayPow(uint256 x, uint256 n) internal pure returns (uint256) {\n return _pow(x, n, RAY, rayMul);\n }\n\n function wadPow(uint256 x, uint256 n) internal pure returns (uint256) {\n return _pow(x, n, WAD, wadMul);\n }\n\n function _pow(\n uint256 x,\n uint256 n,\n uint256 p,\n function(uint256, uint256) internal pure returns (uint256) mul\n ) internal pure returns (uint256 z) {\n z = n % 2 != 0 ? x : p;\n\n for (n /= 2; n != 0; n /= 2) {\n x = mul(x, x);\n\n if (n % 2 != 0) {\n z = mul(z, x);\n }\n }\n }\n}\n" + }, + "contracts/MarketLiquidityRewards.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\nimport \"./interfaces/IMarketLiquidityRewards.sol\";\n\nimport \"./interfaces/IMarketRegistry.sol\";\nimport \"./interfaces/ICollateralManager.sol\";\nimport \"./interfaces/ITellerV2.sol\";\n\nimport { BidState } from \"./TellerV2Storage.sol\";\n\n// Libraries\nimport { MathUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\n\n/*\n- Allocate and claim rewards for loans based on bidId \n\n- Anyone can allocate rewards and an allocation has specific parameters that can be set to incentivise certain types of loans\n \n*/\n\ncontract MarketLiquidityRewards is IMarketLiquidityRewards, Initializable {\n address immutable tellerV2;\n address immutable marketRegistry;\n //address immutable collateralManager;\n\n uint256 allocationCount;\n\n //allocationId => rewardAllocation\n mapping(uint256 => RewardAllocation) public allocatedRewards;\n\n //bidId => allocationId => rewardWasClaimed\n mapping(uint256 => mapping(uint256 => bool)) public rewardClaimedForBid;\n\n modifier onlyMarketOwner(uint256 _marketId) {\n require(\n msg.sender ==\n IMarketRegistry(marketRegistry).getMarketOwner(_marketId),\n \"Only market owner can call this function.\"\n );\n _;\n }\n\n event CreatedAllocation(\n uint256 allocationId,\n address allocator,\n uint256 marketId\n );\n\n event UpdatedAllocation(uint256 allocationId);\n\n event IncreasedAllocation(uint256 allocationId, uint256 amount);\n\n event DecreasedAllocation(uint256 allocationId, uint256 amount);\n\n event DeletedAllocation(uint256 allocationId);\n\n event ClaimedRewards(\n uint256 allocationId,\n uint256 bidId,\n address recipient,\n uint256 amount\n );\n\n constructor(address _tellerV2, address _marketRegistry)\n //address _collateralManager\n {\n tellerV2 = _tellerV2;\n marketRegistry = _marketRegistry;\n //collateralManager = _collateralManager;\n }\n\n function initialize() external initializer {}\n\n /**\n * @notice Creates a new token allocation and transfers the token amount into escrow in this contract\n * @param _allocation - The RewardAllocation struct data to create\n * @return allocationId_\n */\n function allocateRewards(RewardAllocation calldata _allocation)\n public\n virtual\n returns (uint256 allocationId_)\n {\n allocationId_ = allocationCount++;\n\n require(\n _allocation.allocator == msg.sender,\n \"Invalid allocator address\"\n );\n\n require(\n _allocation.requiredPrincipalTokenAddress != address(0),\n \"Invalid required principal token address\"\n );\n\n IERC20Upgradeable(_allocation.rewardTokenAddress).transferFrom(\n msg.sender,\n address(this),\n _allocation.rewardTokenAmount\n );\n\n allocatedRewards[allocationId_] = _allocation;\n\n emit CreatedAllocation(\n allocationId_,\n _allocation.allocator,\n _allocation.marketId\n );\n }\n\n /**\n * @notice Allows the allocator to update properties of an allocation\n * @param _allocationId - The id for the allocation\n * @param _minimumCollateralPerPrincipalAmount - The required collateralization ratio\n * @param _rewardPerLoanPrincipalAmount - The reward to give per principal amount\n * @param _bidStartTimeMin - The block timestamp that loans must have been accepted after to claim rewards\n * @param _bidStartTimeMax - The block timestamp that loans must have been accepted before to claim rewards\n */\n function updateAllocation(\n uint256 _allocationId,\n uint256 _minimumCollateralPerPrincipalAmount,\n uint256 _rewardPerLoanPrincipalAmount,\n uint32 _bidStartTimeMin,\n uint32 _bidStartTimeMax\n ) public virtual {\n RewardAllocation storage allocation = allocatedRewards[_allocationId];\n\n require(\n msg.sender == allocation.allocator,\n \"Only the allocator can update allocation rewards.\"\n );\n\n allocation\n .minimumCollateralPerPrincipalAmount = _minimumCollateralPerPrincipalAmount;\n allocation.rewardPerLoanPrincipalAmount = _rewardPerLoanPrincipalAmount;\n allocation.bidStartTimeMin = _bidStartTimeMin;\n allocation.bidStartTimeMax = _bidStartTimeMax;\n\n emit UpdatedAllocation(_allocationId);\n }\n\n /**\n * @notice Allows anyone to add tokens to an allocation\n * @param _allocationId - The id for the allocation\n * @param _tokenAmount - The amount of tokens to add\n */\n function increaseAllocationAmount(\n uint256 _allocationId,\n uint256 _tokenAmount\n ) public virtual {\n IERC20Upgradeable(allocatedRewards[_allocationId].rewardTokenAddress)\n .transferFrom(msg.sender, address(this), _tokenAmount);\n allocatedRewards[_allocationId].rewardTokenAmount += _tokenAmount;\n\n emit IncreasedAllocation(_allocationId, _tokenAmount);\n }\n\n /**\n * @notice Allows the allocator to withdraw some or all of the funds within an allocation\n * @param _allocationId - The id for the allocation\n * @param _tokenAmount - The amount of tokens to withdraw\n */\n function deallocateRewards(uint256 _allocationId, uint256 _tokenAmount)\n public\n virtual\n {\n require(\n msg.sender == allocatedRewards[_allocationId].allocator,\n \"Only the allocator can deallocate rewards.\"\n );\n\n //enforce that the token amount withdraw must be LEQ to the reward amount for this allocation\n if (_tokenAmount > allocatedRewards[_allocationId].rewardTokenAmount) {\n _tokenAmount = allocatedRewards[_allocationId].rewardTokenAmount;\n }\n\n //subtract amount reward before transfer\n _decrementAllocatedAmount(_allocationId, _tokenAmount);\n\n IERC20Upgradeable(allocatedRewards[_allocationId].rewardTokenAddress)\n .transfer(msg.sender, _tokenAmount);\n\n //if the allocated rewards are drained completely, delete the storage slot for it\n if (allocatedRewards[_allocationId].rewardTokenAmount == 0) {\n delete allocatedRewards[_allocationId];\n\n emit DeletedAllocation(_allocationId);\n } else {\n emit DecreasedAllocation(_allocationId, _tokenAmount);\n }\n }\n\n struct LoanSummary {\n address borrower;\n address lender;\n uint256 marketId;\n address principalTokenAddress;\n uint256 principalAmount;\n uint32 acceptedTimestamp;\n uint32 lastRepaidTimestamp;\n BidState bidState;\n }\n\n function _getLoanSummary(uint256 _bidId)\n internal\n returns (LoanSummary memory _summary)\n {\n (\n _summary.borrower,\n _summary.lender,\n _summary.marketId,\n _summary.principalTokenAddress,\n _summary.principalAmount,\n _summary.acceptedTimestamp,\n _summary.lastRepaidTimestamp,\n _summary.bidState\n ) = ITellerV2(tellerV2).getLoanSummary(_bidId);\n }\n\n /**\n * @notice Allows a borrower or lender to withdraw the allocated ERC20 reward for their loan\n * @param _allocationId - The id for the reward allocation\n * @param _bidId - The id for the loan. Each loan only grants one reward per allocation.\n */\n function claimRewards(uint256 _allocationId, uint256 _bidId)\n external\n virtual\n {\n RewardAllocation storage allocatedReward = allocatedRewards[\n _allocationId\n ];\n\n //set a flag that this reward was claimed for this bid to defend against re-entrancy\n require(\n !rewardClaimedForBid[_bidId][_allocationId],\n \"reward already claimed\"\n );\n rewardClaimedForBid[_bidId][_allocationId] = true;\n\n //make this a struct ?\n LoanSummary memory loanSummary = _getLoanSummary(_bidId); //ITellerV2(tellerV2).getLoanSummary(_bidId);\n\n address collateralTokenAddress = allocatedReward\n .requiredCollateralTokenAddress;\n\n //require that the loan was started in the correct timeframe\n _verifyLoanStartTime(\n loanSummary.acceptedTimestamp,\n allocatedReward.bidStartTimeMin,\n allocatedReward.bidStartTimeMax\n );\n\n ICollateralManager _collateralManager = ITellerV2(tellerV2)\n .getCollateralManagerForBid(_bidId);\n\n //if a collateral token address is set on the allocation, verify that the bid has enough collateral ratio\n if (collateralTokenAddress != address(0)) {\n uint256 collateralAmount = _collateralManager.getCollateralAmount(\n _bidId,\n collateralTokenAddress\n );\n\n //require collateral amount\n _verifyCollateralAmount(\n collateralTokenAddress,\n collateralAmount,\n loanSummary.principalTokenAddress,\n loanSummary.principalAmount,\n allocatedReward.minimumCollateralPerPrincipalAmount\n );\n }\n\n require(\n loanSummary.principalTokenAddress ==\n allocatedReward.requiredPrincipalTokenAddress,\n \"Principal token address mismatch for allocation\"\n );\n\n require(\n loanSummary.marketId == allocatedRewards[_allocationId].marketId,\n \"MarketId mismatch for allocation\"\n );\n\n uint256 principalTokenDecimals = IERC20MetadataUpgradeable(\n loanSummary.principalTokenAddress\n ).decimals();\n\n address rewardRecipient = _verifyAndReturnRewardRecipient(\n allocatedReward.allocationStrategy,\n loanSummary.bidState,\n loanSummary.borrower,\n loanSummary.lender\n );\n\n uint32 loanDuration = loanSummary.lastRepaidTimestamp -\n loanSummary.acceptedTimestamp;\n\n uint256 amountToReward = _calculateRewardAmount(\n loanSummary.principalAmount,\n loanDuration,\n principalTokenDecimals,\n allocatedReward.rewardPerLoanPrincipalAmount\n );\n\n if (amountToReward > allocatedReward.rewardTokenAmount) {\n amountToReward = allocatedReward.rewardTokenAmount;\n }\n\n require(amountToReward > 0, \"Nothing to claim.\");\n\n _decrementAllocatedAmount(_allocationId, amountToReward);\n\n //transfer tokens reward to the msgsender\n IERC20Upgradeable(allocatedRewards[_allocationId].rewardTokenAddress)\n .transfer(rewardRecipient, amountToReward);\n\n emit ClaimedRewards(\n _allocationId,\n _bidId,\n rewardRecipient,\n amountToReward\n );\n }\n\n /**\n * @notice Verifies that the bid state is appropriate for claiming rewards based on the allocation strategy and then returns the address of the reward recipient(borrower or lender)\n * @param _strategy - The strategy for the reward allocation.\n * @param _bidState - The bid state of the loan.\n * @param _borrower - The borrower of the loan.\n * @param _lender - The lender of the loan.\n * @return rewardRecipient_ The address that will receive the rewards. Either the borrower or lender.\n */\n function _verifyAndReturnRewardRecipient(\n AllocationStrategy _strategy,\n BidState _bidState,\n address _borrower,\n address _lender\n ) internal virtual returns (address rewardRecipient_) {\n if (_strategy == AllocationStrategy.BORROWER) {\n require(_bidState == BidState.PAID, \"Invalid bid state for loan.\");\n\n rewardRecipient_ = _borrower;\n } else if (_strategy == AllocationStrategy.LENDER) {\n //Loan must have been accepted in the past\n require(\n _bidState >= BidState.ACCEPTED,\n \"Invalid bid state for loan.\"\n );\n\n rewardRecipient_ = _lender;\n } else {\n revert(\"Unknown allocation strategy\");\n }\n }\n\n /**\n * @notice Decrements the amount allocated to keep track of tokens in escrow\n * @param _allocationId - The id for the allocation to decrement\n * @param _amount - The amount of ERC20 to decrement\n */\n function _decrementAllocatedAmount(uint256 _allocationId, uint256 _amount)\n internal\n {\n allocatedRewards[_allocationId].rewardTokenAmount -= _amount;\n }\n\n /**\n * @notice Calculates the reward to claim for the allocation\n * @param _loanPrincipal - The amount of principal for the loan for which to reward\n * @param _loanDuration - The duration of the loan in seconds\n * @param _principalTokenDecimals - The number of decimals of the principal token\n * @param _rewardPerLoanPrincipalAmount - The amount of reward per loan principal amount, expanded by the principal token decimals\n * @return The amount of ERC20 to reward\n */\n function _calculateRewardAmount(\n uint256 _loanPrincipal,\n uint256 _loanDuration,\n uint256 _principalTokenDecimals,\n uint256 _rewardPerLoanPrincipalAmount\n ) internal view returns (uint256) {\n uint256 rewardPerYear = MathUpgradeable.mulDiv(\n _loanPrincipal,\n _rewardPerLoanPrincipalAmount, //expanded by principal token decimals\n 10**_principalTokenDecimals\n );\n\n return MathUpgradeable.mulDiv(rewardPerYear, _loanDuration, 365 days);\n }\n\n /**\n * @notice Verifies that the collateral ratio for the loan was sufficient based on _minimumCollateralPerPrincipalAmount of the allocation\n * @param _collateralTokenAddress - The contract address for the collateral token\n * @param _collateralAmount - The number of decimals of the collateral token\n * @param _principalTokenAddress - The contract address for the principal token\n * @param _principalAmount - The number of decimals of the principal token\n * @param _minimumCollateralPerPrincipalAmount - The amount of collateral required per principal amount. Expanded by the principal token decimals and collateral token decimals.\n */\n function _verifyCollateralAmount(\n address _collateralTokenAddress,\n uint256 _collateralAmount,\n address _principalTokenAddress,\n uint256 _principalAmount,\n uint256 _minimumCollateralPerPrincipalAmount\n ) internal virtual {\n uint256 principalTokenDecimals = IERC20MetadataUpgradeable(\n _principalTokenAddress\n ).decimals();\n\n uint256 collateralTokenDecimals = IERC20MetadataUpgradeable(\n _collateralTokenAddress\n ).decimals();\n\n uint256 minCollateral = _requiredCollateralAmount(\n _principalAmount,\n principalTokenDecimals,\n collateralTokenDecimals,\n _minimumCollateralPerPrincipalAmount\n );\n\n require(\n _collateralAmount >= minCollateral,\n \"Loan does not meet minimum collateralization ratio.\"\n );\n }\n\n /**\n * @notice Calculates the minimum amount of collateral the loan requires based on principal amount\n * @param _principalAmount - The number of decimals of the principal token\n * @param _principalTokenDecimals - The number of decimals of the principal token\n * @param _collateralTokenDecimals - The number of decimals of the collateral token\n * @param _minimumCollateralPerPrincipalAmount - The amount of collateral required per principal amount. Expanded by the principal token decimals and collateral token decimals.\n */\n function _requiredCollateralAmount(\n uint256 _principalAmount,\n uint256 _principalTokenDecimals,\n uint256 _collateralTokenDecimals,\n uint256 _minimumCollateralPerPrincipalAmount\n ) internal view virtual returns (uint256) {\n return\n MathUpgradeable.mulDiv(\n _principalAmount,\n _minimumCollateralPerPrincipalAmount, //expanded by principal token decimals and collateral token decimals\n 10**(_principalTokenDecimals + _collateralTokenDecimals)\n );\n }\n\n /**\n * @notice Verifies that the loan start time is within the bounds set by the allocation requirements\n * @param _loanStartTime - The timestamp when the loan was accepted\n * @param _minStartTime - The minimum time required, after which the loan must have been accepted\n * @param _maxStartTime - The maximum time required, before which the loan must have been accepted\n */\n function _verifyLoanStartTime(\n uint32 _loanStartTime,\n uint32 _minStartTime,\n uint32 _maxStartTime\n ) internal virtual {\n require(\n _minStartTime == 0 || _loanStartTime > _minStartTime,\n \"Loan was accepted before the min start time.\"\n );\n require(\n _maxStartTime == 0 || _loanStartTime < _maxStartTime,\n \"Loan was accepted after the max start time.\"\n );\n }\n\n /**\n * @notice Returns the amount of reward tokens remaining in the allocation\n * @param _allocationId - The id for the allocation\n */\n function getRewardTokenAmount(uint256 _allocationId)\n public\n view\n override\n returns (uint256)\n {\n return allocatedRewards[_allocationId].rewardTokenAmount;\n }\n}\n" + }, + "contracts/MarketRegistry_G1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Contracts\nimport \"./EAS/TellerAS.sol\";\nimport \"./EAS/TellerASResolver.sol\";\n\n//must continue to use this so storage slots are not broken\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/utils/Context.sol\";\n\n// Interfaces\n \nimport \"./interfaces/IMarketRegistry_V1.sol\";\n\n// Libraries\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { PaymentType } from \"./libraries/V2Calculations.sol\";\n\ncontract MarketRegistry_G1 is \n IMarketRegistry_V1,\n Initializable,\n Context,\n TellerASResolver\n{\n using EnumerableSet for EnumerableSet.AddressSet;\n\n /** Constant Variables **/\n\n uint256 public constant CURRENT_CODE_VERSION = 8;\n\n /* Storage Variables */\n\n struct Marketplace {\n address owner;\n string metadataURI;\n uint16 marketplaceFeePercent; // 10000 is 100%\n bool lenderAttestationRequired;\n EnumerableSet.AddressSet verifiedLendersForMarket;\n mapping(address => bytes32) lenderAttestationIds;\n uint32 paymentCycleDuration; // unix time (seconds)\n uint32 paymentDefaultDuration; //unix time\n uint32 bidExpirationTime; //unix time\n bool borrowerAttestationRequired;\n EnumerableSet.AddressSet verifiedBorrowersForMarket;\n mapping(address => bytes32) borrowerAttestationIds;\n address feeRecipient;\n PaymentType paymentType;\n PaymentCycleType paymentCycleType;\n }\n\n bytes32 public lenderAttestationSchemaId;\n\n mapping(uint256 => Marketplace) internal markets;\n mapping(bytes32 => uint256) internal __uriToId; //DEPRECATED\n uint256 public marketCount;\n bytes32 private _attestingSchemaId;\n bytes32 public borrowerAttestationSchemaId;\n\n uint256 public version;\n\n mapping(uint256 => bool) private marketIsClosed;\n\n TellerAS public tellerAS;\n\n /* Modifiers */\n\n modifier ownsMarket(uint256 _marketId) {\n require(_getMarketOwner(_marketId) == _msgSender(), \"Not the owner\");\n _;\n }\n\n modifier withAttestingSchema(bytes32 schemaId) {\n _attestingSchemaId = schemaId;\n _;\n _attestingSchemaId = bytes32(0);\n }\n\n /* Events */\n\n event MarketCreated(address indexed owner, uint256 marketId);\n event SetMarketURI(uint256 marketId, string uri);\n event SetPaymentCycleDuration(uint256 marketId, uint32 duration); // DEPRECATED - used for subgraph reference\n event SetPaymentCycle(\n uint256 marketId,\n PaymentCycleType paymentCycleType,\n uint32 value\n );\n event SetPaymentDefaultDuration(uint256 marketId, uint32 duration);\n event SetBidExpirationTime(uint256 marketId, uint32 duration);\n event SetMarketFee(uint256 marketId, uint16 feePct);\n event LenderAttestation(uint256 marketId, address lender);\n event BorrowerAttestation(uint256 marketId, address borrower);\n event LenderRevocation(uint256 marketId, address lender);\n event BorrowerRevocation(uint256 marketId, address borrower);\n event MarketClosed(uint256 marketId);\n event LenderExitMarket(uint256 marketId, address lender);\n event BorrowerExitMarket(uint256 marketId, address borrower);\n event SetMarketOwner(uint256 marketId, address newOwner);\n event SetMarketFeeRecipient(uint256 marketId, address newRecipient);\n event SetMarketLenderAttestation(uint256 marketId, bool required);\n event SetMarketBorrowerAttestation(uint256 marketId, bool required);\n event SetMarketPaymentType(uint256 marketId, PaymentType paymentType);\n\n /* External Functions */\n\n function initialize(TellerAS _tellerAS) external initializer {\n tellerAS = _tellerAS;\n\n lenderAttestationSchemaId = tellerAS.getASRegistry().register(\n \"(uint256 marketId, address lenderAddress)\",\n this\n );\n borrowerAttestationSchemaId = tellerAS.getASRegistry().register(\n \"(uint256 marketId, address borrowerAddress)\",\n this\n );\n }\n\n /**\n * @notice Creates a new market.\n * @param _initialOwner Address who will initially own the market.\n * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made.\n * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment.\n * @param _bidExpirationTime Length of time in seconds before pending bids expire.\n * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market.\n * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market.\n * @param _paymentType The payment type for loans in the market.\n * @param _uri URI string to get metadata details about the market.\n * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly\n * @return marketId_ The market ID of the newly created market.\n */\n function createMarket(\n address _initialOwner,\n uint32 _paymentCycleDuration,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n PaymentType _paymentType,\n PaymentCycleType _paymentCycleType,\n string calldata _uri\n ) external returns (uint256 marketId_) {\n marketId_ = _createMarket(\n _initialOwner,\n _paymentCycleDuration,\n _paymentDefaultDuration,\n _bidExpirationTime,\n _feePercent,\n _requireLenderAttestation,\n _requireBorrowerAttestation,\n _paymentType,\n _paymentCycleType,\n _uri\n );\n }\n\n /**\n * @notice Creates a new market.\n * @dev Uses the default EMI payment type.\n * @param _initialOwner Address who will initially own the market.\n * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made.\n * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment.\n * @param _bidExpirationTime Length of time in seconds before pending bids expire.\n * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market.\n * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market.\n * @param _uri URI string to get metadata details about the market.\n * @return marketId_ The market ID of the newly created market.\n */\n function createMarket(\n address _initialOwner,\n uint32 _paymentCycleDuration,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n string calldata _uri\n ) external returns (uint256 marketId_) {\n marketId_ = _createMarket(\n _initialOwner,\n _paymentCycleDuration,\n _paymentDefaultDuration,\n _bidExpirationTime,\n _feePercent,\n _requireLenderAttestation,\n _requireBorrowerAttestation,\n PaymentType.EMI,\n PaymentCycleType.Seconds,\n _uri\n );\n }\n\n /**\n * @notice Creates a new market.\n * @param _initialOwner Address who will initially own the market.\n * @param _paymentCycleDuration Length of time in seconds before a bid's next payment is required to be made.\n * @param _paymentDefaultDuration Length of time in seconds before a loan is considered in default for non-payment.\n * @param _bidExpirationTime Length of time in seconds before pending bids expire.\n * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market.\n * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market.\n * @param _paymentType The payment type for loans in the market.\n * @param _uri URI string to get metadata details about the market.\n * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly\n * @return marketId_ The market ID of the newly created market.\n */\n function _createMarket(\n address _initialOwner,\n uint32 _paymentCycleDuration,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n PaymentType _paymentType,\n PaymentCycleType _paymentCycleType,\n string calldata _uri\n ) internal returns (uint256 marketId_) {\n require(_initialOwner != address(0), \"Invalid owner address\");\n // Increment market ID counter\n marketId_ = ++marketCount;\n\n // Set the market owner\n markets[marketId_].owner = _initialOwner;\n\n // Initialize market settings\n _setMarketSettings(\n marketId_,\n _paymentCycleDuration,\n _paymentType,\n _paymentCycleType,\n _paymentDefaultDuration,\n _bidExpirationTime,\n _feePercent,\n _requireBorrowerAttestation,\n _requireLenderAttestation,\n _uri\n );\n\n emit MarketCreated(_initialOwner, marketId_);\n }\n\n /**\n * @notice Closes a market so new bids cannot be added.\n * @param _marketId The market ID for the market to close.\n */\n\n function closeMarket(uint256 _marketId) public ownsMarket(_marketId) {\n if (!marketIsClosed[_marketId]) {\n marketIsClosed[_marketId] = true;\n\n emit MarketClosed(_marketId);\n }\n }\n\n /**\n * @notice Returns the status of a market existing and not being closed.\n * @param _marketId The market ID for the market to check.\n */\n function isMarketOpen(uint256 _marketId)\n public\n view\n override\n returns (bool)\n {\n return\n markets[_marketId].owner != address(0) &&\n !marketIsClosed[_marketId];\n }\n\n /**\n * @notice Returns the status of a market being open or closed for new bids. Does not indicate whether or not a market exists.\n * @param _marketId The market ID for the market to check.\n */\n function isMarketClosed(uint256 _marketId)\n public\n view\n override\n returns (bool)\n {\n return marketIsClosed[_marketId];\n }\n\n /**\n * @notice Adds a lender to a market.\n * @dev See {_attestStakeholder}.\n */\n function attestLender(\n uint256 _marketId,\n address _lenderAddress,\n uint256 _expirationTime\n ) external {\n _attestStakeholder(_marketId, _lenderAddress, _expirationTime, true);\n }\n\n /**\n * @notice Adds a lender to a market via delegated attestation.\n * @dev See {_attestStakeholderViaDelegation}.\n */\n function attestLender(\n uint256 _marketId,\n address _lenderAddress,\n uint256 _expirationTime,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external {\n _attestStakeholderViaDelegation(\n _marketId,\n _lenderAddress,\n _expirationTime,\n true,\n _v,\n _r,\n _s\n );\n }\n\n /**\n * @notice Removes a lender from an market.\n * @dev See {_revokeStakeholder}.\n */\n function revokeLender(uint256 _marketId, address _lenderAddress) external {\n _revokeStakeholder(_marketId, _lenderAddress, true);\n }\n\n /**\n * @notice Removes a borrower from a market via delegated revocation.\n * @dev See {_revokeStakeholderViaDelegation}.\n */\n function revokeLender(\n uint256 _marketId,\n address _lenderAddress,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external {\n _revokeStakeholderViaDelegation(\n _marketId,\n _lenderAddress,\n true,\n _v,\n _r,\n _s\n );\n }\n\n /**\n * @notice Allows a lender to voluntarily leave a market.\n * @param _marketId The market ID to leave.\n */\n function lenderExitMarket(uint256 _marketId) external {\n // Remove lender address from market set\n bool response = markets[_marketId].verifiedLendersForMarket.remove(\n _msgSender()\n );\n if (response) {\n emit LenderExitMarket(_marketId, _msgSender());\n }\n }\n\n /**\n * @notice Adds a borrower to a market.\n * @dev See {_attestStakeholder}.\n */\n function attestBorrower(\n uint256 _marketId,\n address _borrowerAddress,\n uint256 _expirationTime\n ) external {\n _attestStakeholder(_marketId, _borrowerAddress, _expirationTime, false);\n }\n\n /**\n * @notice Adds a borrower to a market via delegated attestation.\n * @dev See {_attestStakeholderViaDelegation}.\n */\n function attestBorrower(\n uint256 _marketId,\n address _borrowerAddress,\n uint256 _expirationTime,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external {\n _attestStakeholderViaDelegation(\n _marketId,\n _borrowerAddress,\n _expirationTime,\n false,\n _v,\n _r,\n _s\n );\n }\n\n /**\n * @notice Removes a borrower from an market.\n * @dev See {_revokeStakeholder}.\n */\n function revokeBorrower(uint256 _marketId, address _borrowerAddress)\n external\n {\n _revokeStakeholder(_marketId, _borrowerAddress, false);\n }\n\n /**\n * @notice Removes a borrower from a market via delegated revocation.\n * @dev See {_revokeStakeholderViaDelegation}.\n */\n function revokeBorrower(\n uint256 _marketId,\n address _borrowerAddress,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) external {\n _revokeStakeholderViaDelegation(\n _marketId,\n _borrowerAddress,\n false,\n _v,\n _r,\n _s\n );\n }\n\n /**\n * @notice Allows a borrower to voluntarily leave a market.\n * @param _marketId The market ID to leave.\n */\n function borrowerExitMarket(uint256 _marketId) external {\n // Remove borrower address from market set\n bool response = markets[_marketId].verifiedBorrowersForMarket.remove(\n _msgSender()\n );\n if (response) {\n emit BorrowerExitMarket(_marketId, _msgSender());\n }\n }\n\n /**\n * @notice Verifies an attestation is valid.\n * @dev This function must only be called by the `attestLender` function above.\n * @param recipient Lender's address who is being attested.\n * @param schema The schema used for the attestation.\n * @param data Data the must include the market ID and lender's address\n * @param\n * @param attestor Market owner's address who signed the attestation.\n * @return Boolean indicating the attestation was successful.\n */\n function resolve(\n address recipient,\n bytes calldata schema,\n bytes calldata data,\n uint256 /* expirationTime */,\n address attestor\n ) external payable override returns (bool) {\n bytes32 attestationSchemaId = keccak256(\n abi.encodePacked(schema, address(this))\n );\n (uint256 marketId, address lenderAddress) = abi.decode(\n data,\n (uint256, address)\n );\n return\n (_attestingSchemaId == attestationSchemaId &&\n recipient == lenderAddress &&\n attestor == _getMarketOwner(marketId)) ||\n attestor == address(this);\n }\n\n /**\n * @notice Transfers ownership of a marketplace.\n * @param _marketId The ID of a market.\n * @param _newOwner Address of the new market owner.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function transferMarketOwnership(uint256 _marketId, address _newOwner)\n public\n ownsMarket(_marketId)\n {\n markets[_marketId].owner = _newOwner;\n emit SetMarketOwner(_marketId, _newOwner);\n }\n\n /**\n * @notice Updates multiple market settings for a given market.\n * @param _marketId The ID of a market.\n * @param _paymentCycleDuration Delinquency duration for new loans\n * @param _newPaymentType The payment type for the market.\n * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly\n * @param _paymentDefaultDuration Default duration for new loans\n * @param _bidExpirationTime Duration of time before a bid is considered out of date\n * @param _metadataURI A URI that points to a market's metadata.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function updateMarketSettings(\n uint256 _marketId,\n uint32 _paymentCycleDuration,\n PaymentType _newPaymentType,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _borrowerAttestationRequired,\n bool _lenderAttestationRequired,\n string calldata _metadataURI\n ) public ownsMarket(_marketId) {\n _setMarketSettings(\n _marketId,\n _paymentCycleDuration,\n _newPaymentType,\n _paymentCycleType,\n _paymentDefaultDuration,\n _bidExpirationTime,\n _feePercent,\n _borrowerAttestationRequired,\n _lenderAttestationRequired,\n _metadataURI\n );\n }\n\n /**\n * @notice Sets the fee recipient address for a market.\n * @param _marketId The ID of a market.\n * @param _recipient Address of the new fee recipient.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setMarketFeeRecipient(uint256 _marketId, address _recipient)\n public\n ownsMarket(_marketId)\n {\n markets[_marketId].feeRecipient = _recipient;\n emit SetMarketFeeRecipient(_marketId, _recipient);\n }\n\n /**\n * @notice Sets the metadata URI for a market.\n * @param _marketId The ID of a market.\n * @param _uri A URI that points to a market's metadata.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setMarketURI(uint256 _marketId, string calldata _uri)\n public\n ownsMarket(_marketId)\n {\n //We do string comparison by checking the hashes of the strings against one another\n if (\n keccak256(abi.encodePacked(_uri)) !=\n keccak256(abi.encodePacked(markets[_marketId].metadataURI))\n ) {\n markets[_marketId].metadataURI = _uri;\n\n emit SetMarketURI(_marketId, _uri);\n }\n }\n\n /**\n * @notice Sets the duration of new loans for this market before they turn delinquent.\n * @notice Changing this value does not change the terms of existing loans for this market.\n * @param _marketId The ID of a market.\n * @param _paymentCycleType Cycle type (seconds or monthly)\n * @param _duration Delinquency duration for new loans\n */\n function setPaymentCycle(\n uint256 _marketId,\n PaymentCycleType _paymentCycleType,\n uint32 _duration\n ) public ownsMarket(_marketId) {\n require(\n (_paymentCycleType == PaymentCycleType.Seconds) ||\n (_paymentCycleType == PaymentCycleType.Monthly &&\n _duration == 0),\n \"monthly payment cycle duration cannot be set\"\n );\n Marketplace storage market = markets[_marketId];\n uint32 duration = _paymentCycleType == PaymentCycleType.Seconds\n ? _duration\n : 30 days;\n if (\n _paymentCycleType != market.paymentCycleType ||\n duration != market.paymentCycleDuration\n ) {\n markets[_marketId].paymentCycleType = _paymentCycleType;\n markets[_marketId].paymentCycleDuration = duration;\n\n emit SetPaymentCycle(_marketId, _paymentCycleType, duration);\n }\n }\n\n /**\n * @notice Sets the duration of new loans for this market before they turn defaulted.\n * @notice Changing this value does not change the terms of existing loans for this market.\n * @param _marketId The ID of a market.\n * @param _duration Default duration for new loans\n */\n function setPaymentDefaultDuration(uint256 _marketId, uint32 _duration)\n public\n ownsMarket(_marketId)\n {\n if (_duration != markets[_marketId].paymentDefaultDuration) {\n markets[_marketId].paymentDefaultDuration = _duration;\n\n emit SetPaymentDefaultDuration(_marketId, _duration);\n }\n }\n\n function setBidExpirationTime(uint256 _marketId, uint32 _duration)\n public\n ownsMarket(_marketId)\n {\n if (_duration != markets[_marketId].bidExpirationTime) {\n markets[_marketId].bidExpirationTime = _duration;\n\n emit SetBidExpirationTime(_marketId, _duration);\n }\n }\n\n /**\n * @notice Sets the fee for the market.\n * @param _marketId The ID of a market.\n * @param _newPercent The percentage fee in basis points.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setMarketFeePercent(uint256 _marketId, uint16 _newPercent)\n public\n ownsMarket(_marketId)\n {\n require(_newPercent >= 0 && _newPercent <= 10000, \"invalid percent\");\n if (_newPercent != markets[_marketId].marketplaceFeePercent) {\n markets[_marketId].marketplaceFeePercent = _newPercent;\n emit SetMarketFee(_marketId, _newPercent);\n }\n }\n\n /**\n * @notice Set the payment type for the market.\n * @param _marketId The ID of the market.\n * @param _newPaymentType The payment type for the market.\n */\n function setMarketPaymentType(\n uint256 _marketId,\n PaymentType _newPaymentType\n ) public ownsMarket(_marketId) {\n if (_newPaymentType != markets[_marketId].paymentType) {\n markets[_marketId].paymentType = _newPaymentType;\n emit SetMarketPaymentType(_marketId, _newPaymentType);\n }\n }\n\n /**\n * @notice Enable/disables market whitelist for lenders.\n * @param _marketId The ID of a market.\n * @param _required Boolean indicating if the market requires whitelist.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setLenderAttestationRequired(uint256 _marketId, bool _required)\n public\n ownsMarket(_marketId)\n {\n if (_required != markets[_marketId].lenderAttestationRequired) {\n markets[_marketId].lenderAttestationRequired = _required;\n emit SetMarketLenderAttestation(_marketId, _required);\n }\n }\n\n /**\n * @notice Enable/disables market whitelist for borrowers.\n * @param _marketId The ID of a market.\n * @param _required Boolean indicating if the market requires whitelist.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setBorrowerAttestationRequired(uint256 _marketId, bool _required)\n public\n ownsMarket(_marketId)\n {\n if (_required != markets[_marketId].borrowerAttestationRequired) {\n markets[_marketId].borrowerAttestationRequired = _required;\n emit SetMarketBorrowerAttestation(_marketId, _required);\n }\n }\n\n /**\n * @notice Gets the data associated with a market.\n * @param _marketId The ID of a market.\n */\n function getMarketData(uint256 _marketId)\n public\n view\n returns (\n address owner,\n uint32 paymentCycleDuration,\n uint32 paymentDefaultDuration,\n uint32 loanExpirationTime,\n string memory metadataURI,\n uint16 marketplaceFeePercent,\n bool lenderAttestationRequired\n )\n {\n return (\n markets[_marketId].owner,\n markets[_marketId].paymentCycleDuration,\n markets[_marketId].paymentDefaultDuration,\n markets[_marketId].bidExpirationTime,\n markets[_marketId].metadataURI,\n markets[_marketId].marketplaceFeePercent,\n markets[_marketId].lenderAttestationRequired\n );\n }\n\n /**\n * @notice Gets the attestation requirements for a given market.\n * @param _marketId The ID of the market.\n */\n function getMarketAttestationRequirements(uint256 _marketId)\n public\n view\n returns (\n bool lenderAttestationRequired,\n bool borrowerAttestationRequired\n )\n {\n return (\n markets[_marketId].lenderAttestationRequired,\n markets[_marketId].borrowerAttestationRequired\n );\n }\n\n /**\n * @notice Gets the address of a market's owner.\n * @param _marketId The ID of a market.\n * @return The address of a market's owner.\n */\n function getMarketOwner(uint256 _marketId)\n public\n view\n virtual\n override\n returns (address)\n {\n return _getMarketOwner(_marketId);\n }\n\n /**\n * @notice Gets the address of a market's owner.\n * @param _marketId The ID of a market.\n * @return The address of a market's owner.\n */\n function _getMarketOwner(uint256 _marketId)\n internal\n view\n virtual\n returns (address)\n {\n return markets[_marketId].owner;\n }\n\n /**\n * @notice Gets the fee recipient of a market.\n * @param _marketId The ID of a market.\n * @return The address of a market's fee recipient.\n */\n function getMarketFeeRecipient(uint256 _marketId)\n public\n view\n override\n returns (address)\n {\n address recipient = markets[_marketId].feeRecipient;\n\n if (recipient == address(0)) {\n return _getMarketOwner(_marketId);\n }\n\n return recipient;\n }\n\n /**\n * @notice Gets the metadata URI of a market.\n * @param _marketId The ID of a market.\n * @return URI of a market's metadata.\n */\n function getMarketURI(uint256 _marketId)\n public\n view\n override\n returns (string memory)\n {\n return markets[_marketId].metadataURI;\n }\n\n /**\n * @notice Gets the loan delinquent duration of a market.\n * @param _marketId The ID of a market.\n * @return Duration of a loan until it is delinquent.\n * @return The type of payment cycle for loans in the market.\n */\n function getPaymentCycle(uint256 _marketId)\n public\n view\n override\n returns (uint32, PaymentCycleType)\n {\n return (\n markets[_marketId].paymentCycleDuration,\n markets[_marketId].paymentCycleType\n );\n }\n\n /**\n * @notice Gets the loan default duration of a market.\n * @param _marketId The ID of a market.\n * @return Duration of a loan repayment interval until it is default.\n */\n function getPaymentDefaultDuration(uint256 _marketId)\n public\n view\n override\n returns (uint32)\n {\n return markets[_marketId].paymentDefaultDuration;\n }\n\n /**\n * @notice Get the payment type of a market.\n * @param _marketId the ID of the market.\n * @return The type of payment for loans in the market.\n */\n function getPaymentType(uint256 _marketId)\n public\n view\n override\n returns (PaymentType)\n {\n return markets[_marketId].paymentType;\n }\n\n function getBidExpirationTime(uint256 marketId)\n public\n view\n override\n returns (uint32)\n {\n return markets[marketId].bidExpirationTime;\n }\n\n /**\n * @notice Gets the marketplace fee in basis points\n * @param _marketId The ID of a market.\n * @return fee in basis points\n */\n function getMarketplaceFee(uint256 _marketId)\n public\n view\n override\n returns (uint16 fee)\n {\n return markets[_marketId].marketplaceFeePercent;\n }\n\n /**\n * @notice Checks if a lender has been attested and added to a market.\n * @param _marketId The ID of a market.\n * @param _lenderAddress Address to check.\n * @return isVerified_ Boolean indicating if a lender has been added to a market.\n * @return uuid_ Bytes32 representing the UUID of the lender.\n */\n function isVerifiedLender(uint256 _marketId, address _lenderAddress)\n public\n view\n override\n returns (bool isVerified_, bytes32 uuid_)\n {\n return\n _isVerified(\n _lenderAddress,\n markets[_marketId].lenderAttestationRequired,\n markets[_marketId].lenderAttestationIds,\n markets[_marketId].verifiedLendersForMarket\n );\n }\n\n /**\n * @notice Checks if a borrower has been attested and added to a market.\n * @param _marketId The ID of a market.\n * @param _borrowerAddress Address of the borrower to check.\n * @return isVerified_ Boolean indicating if a borrower has been added to a market.\n * @return uuid_ Bytes32 representing the UUID of the borrower.\n */\n function isVerifiedBorrower(uint256 _marketId, address _borrowerAddress)\n public\n view\n override\n returns (bool isVerified_, bytes32 uuid_)\n {\n return\n _isVerified(\n _borrowerAddress,\n markets[_marketId].borrowerAttestationRequired,\n markets[_marketId].borrowerAttestationIds,\n markets[_marketId].verifiedBorrowersForMarket\n );\n }\n\n /**\n * @notice Gets addresses of all attested lenders.\n * @param _marketId The ID of a market.\n * @param _page Page index to start from.\n * @param _perPage Number of items in a page to return.\n * @return Array of addresses that have been added to a market.\n */\n function getAllVerifiedLendersForMarket(\n uint256 _marketId,\n uint256 _page,\n uint256 _perPage\n ) public view returns (address[] memory) {\n EnumerableSet.AddressSet storage set = markets[_marketId]\n .verifiedLendersForMarket;\n\n return _getStakeholdersForMarket(set, _page, _perPage);\n }\n\n /**\n * @notice Gets addresses of all attested borrowers.\n * @param _marketId The ID of the market.\n * @param _page Page index to start from.\n * @param _perPage Number of items in a page to return.\n * @return Array of addresses that have been added to a market.\n */\n function getAllVerifiedBorrowersForMarket(\n uint256 _marketId,\n uint256 _page,\n uint256 _perPage\n ) public view returns (address[] memory) {\n EnumerableSet.AddressSet storage set = markets[_marketId]\n .verifiedBorrowersForMarket;\n return _getStakeholdersForMarket(set, _page, _perPage);\n }\n\n /**\n * @notice Sets multiple market settings for a given market.\n * @param _marketId The ID of a market.\n * @param _paymentCycleDuration Delinquency duration for new loans\n * @param _newPaymentType The payment type for the market.\n * @param _paymentCycleType The payment cycle type for loans in the market - Seconds or Monthly\n * @param _paymentDefaultDuration Default duration for new loans\n * @param _bidExpirationTime Duration of time before a bid is considered out of date\n * @param _metadataURI A URI that points to a market's metadata.\n */\n function _setMarketSettings(\n uint256 _marketId,\n uint32 _paymentCycleDuration,\n PaymentType _newPaymentType,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _borrowerAttestationRequired,\n bool _lenderAttestationRequired,\n string calldata _metadataURI\n ) internal {\n setMarketURI(_marketId, _metadataURI);\n setPaymentDefaultDuration(_marketId, _paymentDefaultDuration);\n setBidExpirationTime(_marketId, _bidExpirationTime);\n setMarketFeePercent(_marketId, _feePercent);\n setLenderAttestationRequired(_marketId, _lenderAttestationRequired);\n setBorrowerAttestationRequired(_marketId, _borrowerAttestationRequired);\n setMarketPaymentType(_marketId, _newPaymentType);\n setPaymentCycle(_marketId, _paymentCycleType, _paymentCycleDuration);\n }\n\n /**\n * @notice Gets addresses of all attested relevant stakeholders.\n * @param _set The stored set of stakeholders to index from.\n * @param _page Page index to start from.\n * @param _perPage Number of items in a page to return.\n * @return stakeholders_ Array of addresses that have been added to a market.\n */\n function _getStakeholdersForMarket(\n EnumerableSet.AddressSet storage _set,\n uint256 _page,\n uint256 _perPage\n ) internal view returns (address[] memory stakeholders_) {\n uint256 len = _set.length();\n\n uint256 start = _page * _perPage;\n if (start <= len) {\n uint256 end = start + _perPage;\n // Ensure we do not go out of bounds\n if (end > len) {\n end = len;\n }\n\n stakeholders_ = new address[](end - start);\n for (uint256 i = start; i < end; i++) {\n stakeholders_[i] = _set.at(i);\n }\n }\n }\n\n /* Internal Functions */\n\n /**\n * @notice Adds a stakeholder (lender or borrower) to a market.\n * @param _marketId The market ID to add a borrower to.\n * @param _stakeholderAddress The address of the stakeholder to add to the market.\n * @param _expirationTime The expiration time of the attestation.\n * @param _expirationTime The expiration time of the attestation.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _attestStakeholder(\n uint256 _marketId,\n address _stakeholderAddress,\n uint256 _expirationTime,\n bool _isLender\n )\n internal\n virtual\n withAttestingSchema(\n _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId\n )\n {\n require(\n _msgSender() == _getMarketOwner(_marketId),\n \"Not the market owner\"\n );\n\n // Submit attestation for borrower to join a market\n bytes32 uuid = tellerAS.attest(\n _stakeholderAddress,\n _attestingSchemaId, // set by the modifier\n _expirationTime,\n 0,\n abi.encode(_marketId, _stakeholderAddress)\n );\n _attestStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n uuid,\n _isLender\n );\n }\n\n /**\n * @notice Adds a stakeholder (lender or borrower) to a market via delegated attestation.\n * @dev The signature must match that of the market owner.\n * @param _marketId The market ID to add a lender to.\n * @param _stakeholderAddress The address of the lender to add to the market.\n * @param _expirationTime The expiration time of the attestation.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n * @param _v Signature value\n * @param _r Signature value\n * @param _s Signature value\n */\n function _attestStakeholderViaDelegation(\n uint256 _marketId,\n address _stakeholderAddress,\n uint256 _expirationTime,\n bool _isLender,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n )\n internal\n virtual\n withAttestingSchema(\n _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId\n )\n {\n // NOTE: block scope to prevent stack too deep!\n bytes32 uuid;\n {\n bytes memory data = abi.encode(_marketId, _stakeholderAddress);\n address attestor = _getMarketOwner(_marketId);\n // Submit attestation for stakeholder to join a market (attestation must be signed by market owner)\n uuid = tellerAS.attestByDelegation(\n _stakeholderAddress,\n _attestingSchemaId, // set by the modifier\n _expirationTime,\n 0,\n data,\n attestor,\n _v,\n _r,\n _s\n );\n }\n _attestStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n uuid,\n _isLender\n );\n }\n\n /**\n * @notice Adds a stakeholder (borrower/lender) to a market.\n * @param _marketId The market ID to add a stakeholder to.\n * @param _stakeholderAddress The address of the stakeholder to add to the market.\n * @param _uuid The UUID of the attestation created.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _attestStakeholderVerification(\n uint256 _marketId,\n address _stakeholderAddress,\n bytes32 _uuid,\n bool _isLender\n ) internal virtual {\n if (_isLender) {\n // Store the lender attestation ID for the market ID\n markets[_marketId].lenderAttestationIds[\n _stakeholderAddress\n ] = _uuid;\n // Add lender address to market set\n markets[_marketId].verifiedLendersForMarket.add(\n _stakeholderAddress\n );\n\n emit LenderAttestation(_marketId, _stakeholderAddress);\n } else {\n // Store the lender attestation ID for the market ID\n markets[_marketId].borrowerAttestationIds[\n _stakeholderAddress\n ] = _uuid;\n // Add lender address to market set\n markets[_marketId].verifiedBorrowersForMarket.add(\n _stakeholderAddress\n );\n\n emit BorrowerAttestation(_marketId, _stakeholderAddress);\n }\n }\n\n /**\n * @notice Removes a stakeholder from an market.\n * @dev The caller must be the market owner.\n * @param _marketId The market ID to remove the borrower from.\n * @param _stakeholderAddress The address of the borrower to remove from the market.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _revokeStakeholder(\n uint256 _marketId,\n address _stakeholderAddress,\n bool _isLender\n ) internal virtual {\n require(\n _msgSender() == _getMarketOwner(_marketId),\n \"Not the market owner\"\n );\n\n bytes32 uuid = _revokeStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n _isLender\n );\n // NOTE: Disabling the call to revoke the attestation on EAS contracts\n // tellerAS.revoke(uuid);\n }\n\n /**\n * @notice Removes a stakeholder from an market via delegated revocation.\n * @param _marketId The market ID to remove the borrower from.\n * @param _stakeholderAddress The address of the borrower to remove from the market.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n * @param _v Signature value\n * @param _r Signature value\n * @param _s Signature value\n */\n function _revokeStakeholderViaDelegation(\n uint256 _marketId,\n address _stakeholderAddress,\n bool _isLender,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) internal {\n bytes32 uuid = _revokeStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n _isLender\n );\n // NOTE: Disabling the call to revoke the attestation on EAS contracts\n // address attestor = markets[_marketId].owner;\n // tellerAS.revokeByDelegation(uuid, attestor, _v, _r, _s);\n }\n\n /**\n * @notice Removes a stakeholder (borrower/lender) from a market.\n * @param _marketId The market ID to remove the lender from.\n * @param _stakeholderAddress The address of the stakeholder to remove from the market.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n * @return uuid_ The ID of the previously verified attestation.\n */\n function _revokeStakeholderVerification(\n uint256 _marketId,\n address _stakeholderAddress,\n bool _isLender\n ) internal virtual returns (bytes32 uuid_) {\n if (_isLender) {\n uuid_ = markets[_marketId].lenderAttestationIds[\n _stakeholderAddress\n ];\n // Remove lender address from market set\n markets[_marketId].verifiedLendersForMarket.remove(\n _stakeholderAddress\n );\n\n emit LenderRevocation(_marketId, _stakeholderAddress);\n } else {\n uuid_ = markets[_marketId].borrowerAttestationIds[\n _stakeholderAddress\n ];\n // Remove borrower address from market set\n markets[_marketId].verifiedBorrowersForMarket.remove(\n _stakeholderAddress\n );\n\n emit BorrowerRevocation(_marketId, _stakeholderAddress);\n }\n }\n\n /**\n * @notice Checks if a stakeholder has been attested and added to a market.\n * @param _stakeholderAddress Address of the stakeholder to check.\n * @param _attestationRequired Stored boolean indicating if attestation is required for the stakeholder class.\n * @param _stakeholderAttestationIds Mapping of attested Ids for the stakeholder class.\n */\n function _isVerified(\n address _stakeholderAddress,\n bool _attestationRequired,\n mapping(address => bytes32) storage _stakeholderAttestationIds,\n EnumerableSet.AddressSet storage _verifiedStakeholderForMarket\n ) internal view virtual returns (bool isVerified_, bytes32 uuid_) {\n if (_attestationRequired) {\n isVerified_ =\n _verifiedStakeholderForMarket.contains(_stakeholderAddress) &&\n tellerAS.isAttestationActive(\n _stakeholderAttestationIds[_stakeholderAddress]\n );\n uuid_ = _stakeholderAttestationIds[_stakeholderAddress];\n } else {\n isVerified_ = true;\n }\n }\n}\n" + }, + "contracts/MarketRegistry_G2.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// Contracts\n//import \"./EAS/TellerAS.sol\";\n//import \"./EAS/TellerASResolver.sol\";\n\n//must continue to use this so storage slots are not broken\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/utils/Context.sol\";\n\n// Interfaces\n\nimport \"./interfaces/IMarketRegistry_V2.sol\";\n\n// Libraries\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { PaymentType } from \"./libraries/V2Calculations.sol\";\n\ncontract MarketRegistry_G2 is\n IMarketRegistry_V2,\n Initializable,\n Context\n{\n using EnumerableSet for EnumerableSet.AddressSet;\n\n /** Constant Variables **/\n\n uint256 public constant CURRENT_CODE_VERSION = 9;\n\n /* Storage Variables */\n\n struct Marketplace {\n address owner;\n string metadataURI;\n uint16 marketplaceFeePercent; //DEPRECATED\n bool lenderAttestationRequired;\n EnumerableSet.AddressSet verifiedLendersForMarket;\n mapping(address => bytes32) _lenderAttestationIds; //DEPRECATED\n uint32 paymentCycleDuration; //DEPRECATED\n uint32 paymentDefaultDuration; //DEPRECATED\n uint32 bidExpirationTime; //DEPRECATED\n bool borrowerAttestationRequired;\n EnumerableSet.AddressSet verifiedBorrowersForMarket;\n mapping(address => bytes32) _borrowerAttestationIds; //DEPRECATED\n address feeRecipient; //DEPRECATED\n PaymentType paymentType; //DEPRECATED\n PaymentCycleType paymentCycleType; //DEPRECATED\n }\n\n bytes32 public __lenderAttestationSchemaId; //DEPRECATED\n\n mapping(uint256 => Marketplace) internal markets;\n mapping(bytes32 => uint256) internal __uriToId; //DEPRECATED\n uint256 public marketCount;\n bytes32 private _attestingSchemaId;\n bytes32 public borrowerAttestationSchemaId;\n\n uint256 public version;\n\n mapping(uint256 => bool) private marketIsClosed;\n\n //uint256 marketTermsCount; // use a hash here instead of uint256\n mapping(bytes32 => MarketplaceTerms) public marketTerms;\n\n //market id => market terms. Used when a new bid is created. If this is blank for a market, new bids cant be created for that market.\n mapping(uint256 => bytes32) public currentMarketTermsForMarket;\n\n //TellerAS public tellerAS; //this took 7 storage slots\n uint256[7] private __teller_as_gap;\n\n /* Modifiers */\n\n modifier ownsMarket(uint256 _marketId) {\n require(_getMarketOwner(_marketId) == _msgSender(), \"Not the owner\");\n _;\n }\n\n /* modifier withAttestingSchema(bytes32 schemaId) {\n _attestingSchemaId = schemaId;\n _;\n _attestingSchemaId = bytes32(0);\n }*/\n\n /* Events */\n\n event MarketCreated(address indexed owner, uint256 marketId);\n event SetMarketURI(uint256 marketId, string uri);\n event SetPaymentCycleDuration(uint256 marketId, uint32 duration); // DEPRECATED - used for subgraph reference\n event SetPaymentCycle(\n uint256 marketId,\n PaymentCycleType paymentCycleType,\n uint32 value\n );\n event SetPaymentDefaultDuration(uint256 marketId, uint32 duration);\n event SetBidExpirationTime(uint256 marketId, uint32 duration);\n event SetMarketFee(uint256 marketId, uint16 feePct);\n event LenderAttestation(uint256 marketId, address lender);\n event BorrowerAttestation(uint256 marketId, address borrower);\n event LenderRevocation(uint256 marketId, address lender);\n event BorrowerRevocation(uint256 marketId, address borrower);\n event MarketClosed(uint256 marketId);\n event LenderExitMarket(uint256 marketId, address lender);\n event BorrowerExitMarket(uint256 marketId, address borrower);\n event SetMarketOwner(uint256 marketId, address newOwner);\n event SetMarketFeeRecipient(uint256 marketId, address newRecipient);\n event SetMarketLenderAttestation(uint256 marketId, bool required);\n event SetMarketBorrowerAttestation(uint256 marketId, bool required);\n event SetMarketPaymentType(uint256 marketId, PaymentType paymentType);\n\n event DefineMarketTerms(bytes32 marketTermsId);\n event SetCurrentMarketTermsForMarket(\n uint256 marketId,\n bytes32 marketTermsId\n );\n\n /* External Functions */\n\n function initialize() external initializer {\n /* tellerAS = _tellerAS;\n\n lenderAttestationSchemaId = tellerAS.getASRegistry().register(\n \"(uint256 marketId, address lenderAddress)\",\n this\n );\n borrowerAttestationSchemaId = tellerAS.getASRegistry().register(\n \"(uint256 marketId, address borrowerAddress)\",\n this\n ); */\n }\n\n /**\n * @notice Creates a new market.\n * @param _initialOwner Address who will initially own the market.\n \n * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market.\n * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market.\n \n * @param _uri URI string to get metadata details about the market.\n * @param _marketTermsParams Parameters to define the market terms.\n \n * @return marketId_ The market ID of the newly created market.\n * @return marketTerms_ The market Terms Hash of the markets terms.\n */\n function createMarket(\n address _initialOwner,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n string calldata _uri,\n MarketplaceTerms memory _marketTermsParams\n ) external returns (uint256 marketId_, bytes32 marketTerms_) {\n marketId_ = _createMarket(\n _initialOwner,\n _requireLenderAttestation,\n _requireBorrowerAttestation,\n _uri\n );\n\n marketTerms_ = _updateMarketSettings(marketId_, _marketTermsParams);\n }\n\n /**\n * @notice Creates a new market.\n * @param _initialOwner Address who will initially own the market.\n \n * @param _requireLenderAttestation Boolean that indicates if lenders require attestation to join market.\n * @param _requireBorrowerAttestation Boolean that indicates if borrowers require attestation to join market.\n \n * @param _uri URI string to get metadata details about the market. \n * @return marketId_ The market ID of the newly created market.\n */\n function _createMarket(\n address _initialOwner,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n string calldata _uri\n ) internal returns (uint256 marketId_) {\n require(_initialOwner != address(0), \"Invalid owner address\");\n // Increment market ID counter\n marketId_ = ++marketCount;\n\n // Set the market owner\n markets[marketId_].owner = _initialOwner;\n markets[marketId_].metadataURI = _uri;\n markets[marketId_]\n .borrowerAttestationRequired = _requireBorrowerAttestation;\n markets[marketId_]\n .lenderAttestationRequired = _requireLenderAttestation;\n\n emit MarketCreated(_initialOwner, marketId_);\n }\n\n /**\n * @notice Closes a market so new bids cannot be added.\n * @param _marketId The market ID for the market to close.\n */\n\n function closeMarket(uint256 _marketId) public ownsMarket(_marketId) {\n if (!marketIsClosed[_marketId]) {\n marketIsClosed[_marketId] = true;\n\n emit MarketClosed(_marketId);\n }\n }\n\n /**\n * @notice Returns the status of a market existing and not being closed.\n * @param _marketId The market ID for the market to check.\n */\n function isMarketOpen(uint256 _marketId)\n public\n view\n override\n returns (bool)\n {\n return\n markets[_marketId].owner != address(0) &&\n !marketIsClosed[_marketId];\n }\n\n /**\n * @notice Returns the status of a market being open or closed for new bids. Does not indicate whether or not a market exists.\n * @param _marketId The market ID for the market to check.\n */\n function isMarketClosed(uint256 _marketId)\n public\n view\n override\n returns (bool)\n {\n return marketIsClosed[_marketId];\n }\n\n /**\n * @notice Transfers ownership of a marketplace.\n * @param _marketId The ID of a market.\n * @param _newOwner Address of the new market owner.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function transferMarketOwnership(uint256 _marketId, address _newOwner)\n public\n ownsMarket(_marketId)\n {\n markets[_marketId].owner = _newOwner;\n emit SetMarketOwner(_marketId, _newOwner);\n }\n\n /**\n * @notice Updates multiple market settings for a given market. Does not affect existing bids only new ones created after.\n * @param _marketId The ID of a market.\n \n * @param _marketTermsParams The new parameters to use for the market terms \n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function updateMarketSettings(\n uint256 _marketId,\n MarketplaceTerms memory _marketTermsParams\n ) public ownsMarket(_marketId) returns (bytes32 marketTermsId_) {\n return _updateMarketSettings(_marketId, _marketTermsParams);\n }\n\n function _updateMarketSettings(\n uint256 _marketId,\n MarketplaceTerms memory _marketTermsParams\n ) internal returns (bytes32 marketTermsId_) {\n marketTermsId_ = _defineNewMarketTermsRevision(\n _marketTermsParams.paymentCycleDuration,\n _marketTermsParams.paymentType,\n _marketTermsParams.paymentCycleType,\n _marketTermsParams.paymentDefaultDuration,\n _marketTermsParams.bidExpirationTime,\n _marketTermsParams.marketplaceFeePercent,\n _marketTermsParams.feeRecipient\n );\n emit DefineMarketTerms(marketTermsId_);\n\n currentMarketTermsForMarket[_marketId] = marketTermsId_;\n emit SetCurrentMarketTermsForMarket(_marketId, marketTermsId_);\n }\n\n function marketHasDefinedTerms(uint256 _marketId)\n public\n view\n returns (bool)\n {\n return currentMarketTermsForMarket[_marketId] != bytes32(0);\n }\n\n function getCurrentTermsForMarket(uint256 _marketId)\n public\n view\n returns (bytes32)\n {\n return currentMarketTermsForMarket[_marketId];\n }\n\n /**\n * @notice Sets the metadata URI for a market.\n * @param _marketId The ID of a market.\n * @param _uri A URI that points to a market's metadata.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setMarketURI(uint256 _marketId, string calldata _uri)\n public\n ownsMarket(_marketId)\n {\n //We do string comparison by checking the hashes of the strings against one another\n if (\n keccak256(abi.encodePacked(_uri)) !=\n keccak256(abi.encodePacked(markets[_marketId].metadataURI))\n ) {\n markets[_marketId].metadataURI = _uri;\n\n emit SetMarketURI(_marketId, _uri);\n }\n }\n\n //need to rebuild this\n /**\n * @notice Gets the data associated with a market.\n * @param _marketId The ID of a market.\n */\n function getMarketData(uint256 _marketId)\n public\n view\n returns (\n address owner,\n string memory metadataURI,\n bool borrowerAttestationRequired,\n bool lenderAttestationRequired,\n bytes32 marketTermsId\n )\n {\n return (\n markets[_marketId].owner,\n markets[_marketId].metadataURI,\n markets[_marketId].borrowerAttestationRequired,\n markets[_marketId].lenderAttestationRequired,\n currentMarketTermsForMarket[_marketId]\n );\n }\n\n function getMarketTermsData(bytes32 _marketTermsId)\n public\n view\n returns (\n uint32 paymentCycleDuration,\n PaymentType paymentType,\n PaymentCycleType paymentCycleType,\n uint32 paymentDefaultDuration,\n uint32 bidExpirationTime,\n uint16 feePercent,\n address feeRecipient\n )\n {\n \n return (\n getPaymentCycleDurationForTerms(_marketTermsId),\n marketTerms[_marketTermsId].paymentType,\n marketTerms[_marketTermsId].paymentCycleType,\n marketTerms[_marketTermsId].paymentDefaultDuration,\n marketTerms[_marketTermsId].bidExpirationTime,\n marketTerms[_marketTermsId].marketplaceFeePercent,\n marketTerms[_marketTermsId].feeRecipient\n );\n }\n\n /**\n * @notice Gets the attestation requirements for a given market.\n * @param _marketId The ID of the market.\n */\n function getMarketAttestationRequirements(uint256 _marketId)\n public\n view\n returns (\n bool lenderAttestationRequired,\n bool borrowerAttestationRequired\n )\n {\n return (\n markets[_marketId].lenderAttestationRequired,\n markets[_marketId].borrowerAttestationRequired\n );\n }\n\n /**\n * @notice Gets the address of a market's owner.\n * @param _marketId The ID of a market.\n * @return The address of a market's owner.\n */\n function getMarketOwner(uint256 _marketId)\n public\n view\n virtual\n override\n returns (address)\n {\n return _getMarketOwner(_marketId);\n }\n\n /**\n * @notice Gets the address of a market's owner.\n * @param _marketId The ID of a market.\n * @return The address of a market's owner.\n */\n function _getMarketOwner(uint256 _marketId)\n internal\n view\n virtual\n returns (address)\n {\n return markets[_marketId].owner;\n }\n\n /**\n * @notice Gets the metadata URI of a market.\n * @param _marketId The ID of a market.\n * @return URI of a market's metadata.\n */\n function getMarketURI(uint256 _marketId)\n public\n view\n override\n returns (string memory)\n {\n return markets[_marketId].metadataURI;\n }\n\n /**\n * @notice Gets the current marketplace fee of a market. This is a carryover to support legacy contracts\n * @dev This is current marketplace fee if a NEW LOAN is created NOT the fee for any legacy loans in this market\n * @param _marketId The ID of a market.\n * @return URI of a market's metadata.\n */\n function getMarketplaceFee(uint256 _marketId)\n external\n view\n returns (uint16)\n {\n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n return marketTerms[_marketTermsId].marketplaceFeePercent;\n }\n\n function getMarketFeeRecipient(uint256 _marketId)\n external\n view\n returns (address _recipient)\n {\n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n _recipient= marketTerms[_marketTermsId].feeRecipient;\n \n\n if (_recipient == address(0)) {\n return _getMarketOwner(_marketId);\n } \n }\n\n \n\n\n /**\n * @notice Gets the loan default duration of a market.\n * @param _marketId The ID of the market.\n * @return Duration of a loan repayment interval until it is default.\n */\n function getPaymentDefaultDuration(uint256 _marketId)\n public\n view\n returns (uint32)\n { \n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n return marketTerms[_marketTermsId].paymentDefaultDuration;\n }\n\n /**\n * @notice Get the payment type of a market.\n * @param _marketId The ID of the market.\n * @return The type of payment for loans in the market.\n */\n function getPaymentType(uint256 _marketId)\n public\n view\n returns (PaymentType)\n {\n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n return marketTerms[_marketTermsId].paymentType;\n }\n\n function getPaymentCycleType(uint256 _marketId)\n public\n view\n returns (PaymentCycleType)\n {\n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n return marketTerms[_marketTermsId].paymentCycleType;\n }\n\n function getPaymentCycleDuration(uint256 _marketId)\n public\n view\n returns (uint32)\n {\n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n return getPaymentCycleDurationForTerms(_marketTermsId);\n }\n\n /**\n * @notice Gets the loan default duration of a market.\n * @param _marketId The ID of the market.\n * @return Expiration of a loan bid submission until it is no longer acceptable.\n */\n function getBidExpirationTime(uint256 _marketId)\n public\n view\n returns (\n //override\n uint32\n )\n {\n bytes32 _marketTermsId = currentMarketTermsForMarket[_marketId];\n return marketTerms[_marketTermsId].bidExpirationTime;\n }\n\n\n\n\n function getMarketFeeTerms(bytes32 _marketTermsId)\n public\n view\n returns (address, uint16)\n {\n return (\n marketTerms[_marketTermsId].feeRecipient,\n marketTerms[_marketTermsId].marketplaceFeePercent\n );\n }\n\n function getMarketTermsForLending(bytes32 _marketTermsId)\n public\n view\n returns (uint32, PaymentCycleType, PaymentType, uint32, uint32)\n {\n require(_marketTermsId != bytes32(0), \"Invalid market terms.\");\n\n uint32 paymentCycleDuration = getPaymentCycleDurationForTerms(_marketTermsId);\n\n return (\n paymentCycleDuration,\n marketTerms[_marketTermsId].paymentCycleType,\n marketTerms[_marketTermsId].paymentType,\n marketTerms[_marketTermsId].paymentDefaultDuration,\n marketTerms[_marketTermsId].bidExpirationTime\n );\n } \n\n\n\n\n /**\n * @notice Gets the loan default duration of a market.\n * @param _marketTermsId The ID of the market terms.\n * @return Duration of a loan repayment interval until it is default.\n */\n function getPaymentDefaultDurationForTerms(bytes32 _marketTermsId)\n public\n view\n returns (uint32)\n {\n return marketTerms[_marketTermsId].paymentDefaultDuration;\n }\n\n /**\n * @notice Get the payment type of a market.\n * @param _marketTermsId the ID of the market terms.\n * @return The type of payment for loans in the market.\n */\n function getPaymentTypeForTerms(bytes32 _marketTermsId)\n public\n view\n returns (PaymentType)\n {\n return marketTerms[_marketTermsId].paymentType;\n }\n\n function getPaymentCycleTypeForTerms(bytes32 _marketTermsId)\n public\n view\n returns (PaymentCycleType)\n {\n return marketTerms[_marketTermsId].paymentCycleType;\n }\n\n function getPaymentCycleDurationForTerms(bytes32 _marketTermsId)\n public\n view\n returns (uint32)\n {\n if(marketTerms[_marketTermsId].paymentCycleType == PaymentCycleType.Monthly){\n return 30 days;\n }\n\n return marketTerms[_marketTermsId].paymentCycleDuration;\n }\n\n /**\n * @notice Gets the loan default duration of a market.\n * @param _marketTermsId The ID of the market terms.\n * @return Expiration of a loan bid submission until it is no longer acceptable.\n */\n function getBidExpirationTimeForTerms(bytes32 _marketTermsId)\n public\n view\n returns (\n //override\n uint32\n )\n {\n return marketTerms[_marketTermsId].bidExpirationTime;\n }\n\n /**\n * @notice Checks if a lender has been attested and added to a market.\n * @param _marketId The ID of a market.\n * @param _lender Address to check.\n * @return isVerified_ Boolean indicating if a lender has been added to a market.\n * @return uuid_ This is now deprecated and blank\n */\n function isVerifiedLender(uint256 _marketId, address _lender)\n public\n view\n override\n returns (bool isVerified_, bytes32 uuid_)\n {\n isVerified_ = _isVerified(\n _lender,\n markets[_marketId].lenderAttestationRequired,\n //markets[_marketId].lenderAttestationIds,\n markets[_marketId].verifiedLendersForMarket\n );\n }\n\n /**\n * @notice Checks if a borrower has been attested and added to a market.\n * @param _marketId The ID of a market.\n * @param _borrower Address of the borrower to check.\n * @return isVerified_ Boolean indicating if a borrower has been added to a market.\n * @return uuid_ This is now deprecated and blank\n */\n function isVerifiedBorrower(uint256 _marketId, address _borrower)\n public\n view\n override\n returns (bool isVerified_, bytes32 uuid_)\n {\n isVerified_ = _isVerified(\n _borrower,\n markets[_marketId].borrowerAttestationRequired,\n //markets[_marketId].borrowerAttestationIds,\n markets[_marketId].verifiedBorrowersForMarket\n );\n }\n\n /**\n * @notice Gets addresses of all attested lenders.\n * @param _marketId The ID of a market.\n * @param _page Page index to start from.\n * @param _perPage Number of items in a page to return.\n * @return Array of addresses that have been added to a market.\n */\n function getAllVerifiedLendersForMarket(\n uint256 _marketId,\n uint256 _page,\n uint256 _perPage\n ) public view returns (address[] memory) {\n EnumerableSet.AddressSet storage set = markets[_marketId]\n .verifiedLendersForMarket;\n\n return _getStakeholdersForMarket(set, _page, _perPage);\n }\n\n /**\n * @notice Gets addresses of all attested borrowers.\n * @param _marketId The ID of the market.\n * @param _page Page index to start from.\n * @param _perPage Number of items in a page to return.\n * @return Array of addresses that have been added to a market.\n */\n function getAllVerifiedBorrowersForMarket(\n uint256 _marketId,\n uint256 _page,\n uint256 _perPage\n ) public view returns (address[] memory) {\n EnumerableSet.AddressSet storage set = markets[_marketId]\n .verifiedBorrowersForMarket;\n return _getStakeholdersForMarket(set, _page, _perPage);\n }\n\n /* function _setMarketSettings(\n uint256 _marketId,\n uint32 _paymentCycleDuration,\n PaymentType _newPaymentType,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n bool _borrowerAttestationRequired,\n bool _lenderAttestationRequired,\n string calldata _metadataURI\n ) internal {\n setMarketURI(_marketId, _metadataURI);\n setPaymentDefaultDuration(_marketId, _paymentDefaultDuration);\n setBidExpirationTime(_marketId, _bidExpirationTime);\n setMarketFeePercent(_marketId, _feePercent);\n setLenderAttestationRequired(_marketId, _lenderAttestationRequired);\n setBorrowerAttestationRequired(_marketId, _borrowerAttestationRequired);\n setMarketPaymentType(_marketId, _newPaymentType);\n setPaymentCycle(_marketId, _paymentCycleType, _paymentCycleDuration);\n }*/\n\n function _defineNewMarketTermsRevision(\n uint32 _paymentCycleDuration,\n PaymentType _newPaymentType,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n address _feeRecipient\n ) internal returns (bytes32) {\n\n require(\n (_paymentCycleType == PaymentCycleType.Seconds) ||\n (_paymentCycleType == PaymentCycleType.Monthly &&\n _paymentCycleDuration == 0),\n \"Monthly payment cycle duration invalid for cycle type\"\n );\n\n bytes32 marketTermsId = _getMarketTermsHashId(\n _paymentCycleDuration,\n _newPaymentType,\n _paymentCycleType,\n _paymentDefaultDuration,\n _bidExpirationTime,\n _feePercent,\n _feeRecipient\n );\n\n marketTerms[marketTermsId] = MarketplaceTerms({\n paymentCycleDuration: _paymentCycleDuration,\n paymentType: _newPaymentType,\n paymentCycleType: _paymentCycleType,\n paymentDefaultDuration: _paymentDefaultDuration,\n bidExpirationTime: _bidExpirationTime,\n marketplaceFeePercent: _feePercent,\n feeRecipient: _feeRecipient\n });\n\n return marketTermsId;\n }\n\n function _getMarketTermsHashId(\n uint32 _paymentCycleDuration,\n PaymentType _newPaymentType,\n PaymentCycleType _paymentCycleType,\n uint32 _paymentDefaultDuration,\n uint32 _bidExpirationTime,\n uint16 _feePercent,\n address _feeRecipient\n ) public view returns (bytes32) {\n return\n keccak256(\n abi.encode(\n _paymentCycleDuration,\n _newPaymentType,\n _paymentCycleType,\n _paymentDefaultDuration,\n _bidExpirationTime,\n _feePercent,\n _feeRecipient\n )\n );\n }\n\n //Attestation Functions\n\n/**\n * @notice Enable/disables market whitelist for lenders.\n * @param _marketId The ID of a market.\n * @param _required Boolean indicating if the market requires whitelist.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setLenderAttestationRequired(uint256 _marketId, bool _required)\n public\n ownsMarket(_marketId)\n {\n if (_required != markets[_marketId].lenderAttestationRequired) {\n markets[_marketId].lenderAttestationRequired = _required;\n emit SetMarketLenderAttestation(_marketId, _required);\n }\n }\n\n /**\n * @notice Enable/disables market whitelist for borrowers.\n * @param _marketId The ID of a market.\n * @param _required Boolean indicating if the market requires whitelist.\n *\n * Requirements:\n * - The caller must be the current owner.\n */\n function setBorrowerAttestationRequired(uint256 _marketId, bool _required)\n public\n ownsMarket(_marketId)\n {\n if (_required != markets[_marketId].borrowerAttestationRequired) {\n markets[_marketId].borrowerAttestationRequired = _required;\n emit SetMarketBorrowerAttestation(_marketId, _required);\n }\n }\n\n /**\n * @notice Adds a lender to a market.\n * @dev See {_attestStakeholder}.\n */\n function attestLender(\n uint256 _marketId,\n address _lenderAddress,\n uint256 _expirationTime\n ) external {\n _attestStakeholder(_marketId, _lenderAddress, _expirationTime, true);\n }\n\n /**\n * @notice Removes a lender from an market.\n * @dev See {_revokeStakeholder}.\n */\n function revokeLender(uint256 _marketId, address _lenderAddress) external {\n _revokeStakeholder(_marketId, _lenderAddress, true);\n }\n\n /**\n * @notice Allows a lender to voluntarily leave a market.\n * @param _marketId The market ID to leave.\n */\n function lenderExitMarket(uint256 _marketId) external {\n // Remove lender address from market set\n bool response = markets[_marketId].verifiedLendersForMarket.remove(\n _msgSender()\n );\n if (response) {\n emit LenderExitMarket(_marketId, _msgSender());\n }\n }\n\n /**\n * @notice Adds a borrower to a market.\n * @dev See {_attestStakeholder}.\n */\n function attestBorrower(\n uint256 _marketId,\n address _borrowerAddress,\n uint256 _expirationTime\n ) external {\n _attestStakeholder(_marketId, _borrowerAddress, _expirationTime, false);\n }\n\n /**\n * @notice Removes a borrower from an market.\n * @dev See {_revokeStakeholder}.\n */\n function revokeBorrower(uint256 _marketId, address _borrowerAddress)\n external\n {\n _revokeStakeholder(_marketId, _borrowerAddress, false);\n }\n\n /**\n * @notice Allows a borrower to voluntarily leave a market.\n * @param _marketId The market ID to leave.\n */\n function borrowerExitMarket(uint256 _marketId) external {\n // Remove borrower address from market set\n bool response = markets[_marketId].verifiedBorrowersForMarket.remove(\n _msgSender()\n );\n if (response) {\n emit BorrowerExitMarket(_marketId, _msgSender());\n }\n }\n\n /**\n * @notice Verifies an attestation is valid.\n * @dev This function must only be called by the `attestLender` function above.\n * @param recipient Lender's address who is being attested.\n * @param schema The schema used for the attestation.\n * @param data Data the must include the market ID and lender's address\n * @param\n * @param attestor Market owner's address who signed the attestation.\n * @return Boolean indicating the attestation was successful.\n */\n /* function resolve(\n address recipient,\n bytes calldata schema,\n bytes calldata data,\n uint256 , // uint256 expirationTime ,\n address attestor\n ) external payable override returns (bool) {\n bytes32 attestationSchemaId = keccak256(\n abi.encodePacked(schema, address(this))\n );\n (uint256 marketId, address lenderAddress) = abi.decode(\n data,\n (uint256, address)\n );\n return\n (_attestingSchemaId == attestationSchemaId &&\n recipient == lenderAddress &&\n attestor == _getMarketOwner(marketId)) ||\n attestor == address(this);\n }*/\n\n /**\n * @notice Gets addresses of all attested relevant stakeholders.\n * @param _set The stored set of stakeholders to index from.\n * @param _page Page index to start from.\n * @param _perPage Number of items in a page to return.\n * @return stakeholders_ Array of addresses that have been added to a market.\n */\n function _getStakeholdersForMarket(\n EnumerableSet.AddressSet storage _set,\n uint256 _page,\n uint256 _perPage\n ) internal view returns (address[] memory stakeholders_) {\n uint256 len = _set.length();\n\n uint256 start = _page * _perPage;\n if (start <= len) {\n uint256 end = start + _perPage;\n // Ensure we do not go out of bounds\n if (end > len) {\n end = len;\n }\n\n stakeholders_ = new address[](end - start);\n for (uint256 i = start; i < end; i++) {\n stakeholders_[i] = _set.at(i);\n }\n }\n }\n\n /* Internal Functions */\n\n /**\n * @notice Adds a stakeholder (lender or borrower) to a market.\n * @param _marketId The market ID to add a borrower to.\n * @param _stakeholderAddress The address of the stakeholder to add to the market.\n * @param _expirationTime The expiration time of the attestation.\n * @param _expirationTime The expiration time of the attestation.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _attestStakeholder(\n uint256 _marketId,\n address _stakeholderAddress,\n uint256 _expirationTime,\n bool _isLender\n )\n internal\n virtual\n /* withAttestingSchema(\n _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId\n )*/\n {\n require(\n _msgSender() == _getMarketOwner(_marketId),\n \"Not the market owner\"\n );\n\n // Submit attestation for borrower to join a market\n /* bytes32 uuid = tellerAS.attest(\n _stakeholderAddress,\n _attestingSchemaId, // set by the modifier\n _expirationTime,\n 0,\n abi.encode(_marketId, _stakeholderAddress)\n );*/\n _attestStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n // uuid,\n _isLender\n );\n }\n\n /* function _attestStakeholderViaDelegation(\n uint256 _marketId,\n address _stakeholderAddress,\n uint256 _expirationTime,\n bool _isLender,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n )\n internal\n virtual\n withAttestingSchema(\n _isLender ? lenderAttestationSchemaId : borrowerAttestationSchemaId\n )\n {\n // NOTE: block scope to prevent stack too deep!\n bytes32 uuid;\n {\n bytes memory data = abi.encode(_marketId, _stakeholderAddress);\n address attestor = _getMarketOwner(_marketId);\n // Submit attestation for stakeholder to join a market (attestation must be signed by market owner)\n uuid = tellerAS.attestByDelegation(\n _stakeholderAddress,\n _attestingSchemaId, // set by the modifier\n _expirationTime,\n 0,\n data,\n attestor,\n _v,\n _r,\n _s\n );\n }\n _attestStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n uuid,\n _isLender\n );\n }*/\n\n /**\n * @notice Adds a stakeholder (borrower/lender) to a market.\n * @param _marketId The market ID to add a stakeholder to.\n * @param _stakeholderAddress The address of the stakeholder to add to the market.\n \n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _attestStakeholderVerification(\n uint256 _marketId,\n address _stakeholderAddress,\n // bytes32 _uuid,\n bool _isLender\n ) internal virtual {\n if (_isLender) {\n // Store the lender attestation ID for the market ID\n /* markets[_marketId].lenderAttestationIds[\n _stakeholderAddress\n ] = _uuid;*/\n // Add lender address to market set\n markets[_marketId].verifiedLendersForMarket.add(\n _stakeholderAddress\n );\n\n emit LenderAttestation(_marketId, _stakeholderAddress);\n } else {\n // Store the lender attestation ID for the market ID\n /* markets[_marketId].borrowerAttestationIds[\n _stakeholderAddress\n ] = _uuid;*/\n // Add lender address to market set\n markets[_marketId].verifiedBorrowersForMarket.add(\n _stakeholderAddress\n );\n\n emit BorrowerAttestation(_marketId, _stakeholderAddress);\n }\n }\n\n /**\n * @notice Removes a stakeholder from an market.\n * @dev The caller must be the market owner.\n * @param _marketId The market ID to remove the borrower from.\n * @param _stakeholderAddress The address of the borrower to remove from the market.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _revokeStakeholder(\n uint256 _marketId,\n address _stakeholderAddress,\n bool _isLender\n ) internal virtual {\n require(\n _msgSender() == _getMarketOwner(_marketId),\n \"Not the market owner\"\n );\n\n _revokeStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n _isLender\n );\n\n /* bytes32 uuid = _revokeStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n _isLender\n );*/\n // NOTE: Disabling the call to revoke the attestation on EAS contracts\n // tellerAS.revoke(uuid);\n }\n\n /**\n * @notice Removes a stakeholder from an market via delegated revocation.\n * @param _marketId The market ID to remove the borrower from.\n * @param _stakeholderAddress The address of the borrower to remove from the market.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n * @param _v Signature value\n * @param _r Signature value\n * @param _s Signature value\n */\n /* function _revokeStakeholderViaDelegation(\n uint256 _marketId,\n address _stakeholderAddress,\n bool _isLender,\n uint8 _v,\n bytes32 _r,\n bytes32 _s\n ) internal {\n bytes32 uuid = _revokeStakeholderVerification(\n _marketId,\n _stakeholderAddress,\n _isLender\n );\n // NOTE: Disabling the call to revoke the attestation on EAS contracts\n // address attestor = markets[_marketId].owner;\n // tellerAS.revokeByDelegation(uuid, attestor, _v, _r, _s);\n }*/\n\n /**\n * @notice Removes a stakeholder (borrower/lender) from a market.\n * @param _marketId The market ID to remove the lender from.\n * @param _stakeholderAddress The address of the stakeholder to remove from the market.\n * @param _isLender Boolean indicating if the stakeholder is a lender. Otherwise it is a borrower.\n */\n function _revokeStakeholderVerification(\n uint256 _marketId,\n address _stakeholderAddress,\n bool _isLender\n ) internal virtual {\n if (_isLender) {\n /*uuid_ = markets[_marketId].lenderAttestationIds[\n _stakeholderAddress\n ];*/\n // Remove lender address from market set\n markets[_marketId].verifiedLendersForMarket.remove(\n _stakeholderAddress\n );\n\n emit LenderRevocation(_marketId, _stakeholderAddress);\n } else {\n /*uuid_ = markets[_marketId].borrowerAttestationIds[\n _stakeholderAddress\n ];*/\n // Remove borrower address from market set\n markets[_marketId].verifiedBorrowersForMarket.remove(\n _stakeholderAddress\n );\n\n emit BorrowerRevocation(_marketId, _stakeholderAddress);\n }\n }\n\n /**\n * @notice Checks if a stakeholder has been attested and added to a market.\n * @param _stakeholderAddress Address of the stakeholder to check.\n * @param _attestationRequired Stored boolean indicating if attestation is required for the stakeholder class.\n \n */\n function _isVerified(\n address _stakeholderAddress,\n bool _attestationRequired,\n //mapping(address => bytes32) storage _stakeholderAttestationIds,\n EnumerableSet.AddressSet storage _verifiedStakeholderForMarket\n ) internal view virtual returns (bool isVerified_) {\n if (_attestationRequired) {\n isVerified_ = _verifiedStakeholderForMarket.contains(\n _stakeholderAddress\n ); /*&&\n tellerAS.isAttestationActive(\n _stakeholderAttestationIds[_stakeholderAddress]\n );*/\n // uuid_ = _stakeholderAttestationIds[_stakeholderAddress];\n } else {\n isVerified_ = true;\n }\n }\n}\n" + }, + "contracts/MarketRegistry.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.0;\n\nimport \"./MarketRegistry_G2.sol\";\n\ncontract MarketRegistry is MarketRegistry_G2 {\n /*constructor(address _tellerV2, address _marketRegistry)\n MarketRegistry_G2(_tellerV2, _marketRegistry)\n {\n // we only want this on an proxy deployment so it only affects the impl\n //_disableInitializers();\n }*/\n}\n" + }, + "contracts/mock/LenderCommitmentForwarderMock.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n//import \"../TellerV2MarketForwarder.sol\";\n\nimport \"../TellerV2Context.sol\";\n\n//import { LenderCommitmentForwarder } from \"../contracts/LenderCommitmentForwarder.sol\";\n\nimport \"../interfaces/ITellerV2.sol\";\nimport \"../interfaces/ILenderCommitmentForwarder.sol\";\n\nimport \"../interfaces/ITellerV2MarketForwarder.sol\";\n\nimport { Collateral, CollateralType } from \"../interfaces/escrow/ICollateralEscrowV1.sol\";\n\nimport \"../mock/MarketRegistryMock.sol\";\n\ncontract LenderCommitmentForwarderMock is\n ILenderCommitmentForwarder,\n ITellerV2MarketForwarder\n{\n mapping(uint256 => Commitment) public commitments;\n\n uint256 commitmentCount;\n\n bool public submitBidWithCollateralWasCalled;\n bool public acceptBidWasCalled;\n bool public submitBidWasCalled;\n bool public acceptCommitmentWithRecipientWasCalled;\n bool public acceptCommitmentWithRecipientAndProofWasCalled;\n\n mapping(uint256 => uint256) public commitmentPrincipalAccepted;\n\n constructor() {}\n\n function createCommitment(\n Commitment calldata _commitment,\n address[] calldata _borrowerAddressList\n ) external returns (uint256) {}\n\n function setCommitment(uint256 _commitmentId, Commitment memory _commitment)\n public\n {\n commitments[_commitmentId] = _commitment;\n }\n\n function getCommitmentLender(uint256 _commitmentId)\n public\n view\n returns (address)\n {\n return commitments[_commitmentId].lender;\n }\n\n function getCommitmentMarketId(uint256 _commitmentId)\n public\n view\n returns (uint256)\n {\n return commitments[_commitmentId].marketId;\n }\n\n function getCommitmentAcceptedPrincipal(uint256 _commitmentId)\n public\n view\n returns (uint256)\n {\n return commitmentPrincipalAccepted[_commitmentId];\n }\n\n function getCommitmentMaxPrincipal(uint256 _commitmentId)\n public\n view\n returns (uint256)\n {\n return commitments[_commitmentId].maxPrincipal;\n }\n\n /* function _getEscrowCollateralTypeSuper(CommitmentCollateralType _type)\n public\n returns (CollateralType)\n {\n return super._getEscrowCollateralType(_type);\n }\n\n function validateCommitmentSuper(uint256 _commitmentId) public {\n super.validateCommitment(commitments[_commitmentId]);\n }*/\n\n function acceptCommitmentWithRecipient(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration\n ) public returns (uint256 bidId) {\n acceptCommitmentWithRecipientWasCalled = true;\n\n Commitment storage commitment = commitments[_commitmentId];\n\n address lendingToken = commitment.principalTokenAddress;\n\n _mockAcceptCommitmentTokenTransfer(\n lendingToken,\n _principalAmount,\n _recipient\n );\n }\n\n function acceptCommitmentWithRecipientAndProof(\n uint256 _commitmentId,\n uint256 _principalAmount,\n uint256 _collateralAmount,\n uint256 _collateralTokenId,\n address _collateralTokenAddress,\n address _recipient,\n uint16 _interestRate,\n uint32 _loanDuration,\n bytes32[] calldata _merkleProof\n ) public returns (uint256 bidId) {\n acceptCommitmentWithRecipientAndProofWasCalled = true;\n\n Commitment storage commitment = commitments[_commitmentId];\n\n address lendingToken = commitment.principalTokenAddress;\n\n _mockAcceptCommitmentTokenTransfer(\n lendingToken,\n _principalAmount,\n _recipient\n );\n }\n\n function _mockAcceptCommitmentTokenTransfer(\n address lendingToken,\n uint256 principalAmount,\n address _recipient\n ) internal {\n IERC20(lendingToken).transfer(_recipient, principalAmount);\n }\n\n /*\n Override methods \n */\n\n /* function _submitBid(CreateLoanArgs memory, address)\n internal\n override\n returns (uint256 bidId)\n {\n submitBidWasCalled = true;\n return 1;\n }\n\n function _submitBidWithCollateral(CreateLoanArgs memory, address)\n internal\n override\n returns (uint256 bidId)\n {\n submitBidWithCollateralWasCalled = true;\n return 1;\n }\n\n function _acceptBid(uint256, address) internal override returns (bool) {\n acceptBidWasCalled = true;\n\n return true;\n }\n */\n}\n" + }, + "contracts/mock/MarketRegistryMock.sol": { + "content": "pragma solidity ^0.8.0;\n\n// SPDX-License-Identifier: MIT\nimport \"../interfaces/IMarketRegistry.sol\";\nimport \"../interfaces/IMarketRegistry_V2.sol\";\nimport { PaymentType } from \"../libraries/V2Calculations.sol\";\n\ncontract MarketRegistryMock is IMarketRegistry, IMarketRegistry_V2 {\n //address marketOwner;\n\n address public globalMarketOwner;\n address public globalMarketFeeRecipient;\n bool public globalMarketsClosed;\n\n bool public globalBorrowerIsVerified = true;\n bool public globalLenderIsVerified = true;\n\n bytes32 public globalTermsForMarket;\n\n constructor() {}\n\n // function initialize(TellerAS _tellerAS) external {}\n\n function getCurrentTermsForMarket(\n uint256 _marketId\n ) public view returns (bytes32) {\n return globalTermsForMarket;\n }\n\n function forceSetGlobalTermsForMarket(bytes32 _term) public {\n globalTermsForMarket = _term;\n }\n\n function isMarketOpen(uint256 _marketId) public view returns (bool) {\n return !globalMarketsClosed;\n \n }\n\n function isMarketClosed(uint256 _marketId) public view returns (bool) {\n return globalMarketsClosed;\n }\n\n function isVerifiedBorrower(\n uint256 _marketId,\n address _borrower\n ) public view returns (bool isVerified_, bytes32) {\n isVerified_ = globalBorrowerIsVerified;\n }\n\n function isVerifiedLender(\n uint256 _marketId,\n address _lenderAddress\n ) public view returns (bool isVerified_, bytes32) {\n isVerified_ = globalLenderIsVerified;\n }\n\n function getMarketOwner(\n uint256 _marketId\n ) public view override returns (address) {\n return address(globalMarketOwner);\n }\n\n function getMarketFeeRecipient(\n uint256 _marketId\n ) public view returns (address) {\n return address(globalMarketFeeRecipient);\n }\n\n function getMarketURI(\n uint256 _marketId\n ) public view returns (string memory) {\n return \"url://\";\n }\n\n function getPaymentType(\n uint256 _marketId\n ) public view returns (PaymentType) {\n return PaymentType.EMI;\n }\n\n function getPaymentCycleDuration(\n uint256 _marketId\n ) public view returns (uint32) {\n return 1000;\n }\n\n function getPaymentCycleType(\n uint256 _marketId\n ) external view returns (PaymentCycleType) {\n return PaymentCycleType.Seconds;\n }\n\n function getPaymentDefaultDuration(\n uint256 _marketId\n ) public view returns (uint32) {\n return 1000;\n }\n\n function getBidExpirationTime(\n uint256 _marketId\n ) public view returns (uint32) {\n return 1000;\n }\n\n //the current marketplace fee if a new loan is created NOT for existing loans in this market\n function getMarketplaceFee(uint256 _marketId) public view returns (uint16) {\n return 1000;\n }\n\n function setMarketOwner(address _owner) public {\n globalMarketOwner = _owner;\n }\n\n function setMarketFeeRecipient(address _feeRecipient) public {\n globalMarketFeeRecipient = _feeRecipient;\n }\n\n function getMarketFeeTerms(\n bytes32 _marketTermsId\n ) public view returns (address, uint16) {\n return (address(this), 2000);\n }\n\n function getMarketTermsForLending(\n bytes32 _marketTermsId\n )\n public\n view\n returns (uint32, PaymentCycleType, PaymentType, uint32, uint32)\n {\n return (2000, PaymentCycleType.Seconds, PaymentType.EMI, 4000, 5000);\n }\n\n function getBidExpirationTimeForTerms(\n bytes32 _marketTermsId\n ) external view returns (uint32) {\n return 4000;\n }\n\n function getPaymentDefaultDurationForTerms(\n bytes32 _marketTermsId\n ) external view returns (uint32) {\n return 6000;\n }\n\n function getPaymentTypeForTerms(\n bytes32 _marketTermsId\n ) external view returns (PaymentType) {\n return PaymentType.EMI;\n }\n\n function getPaymentCycleTypeForTerms(\n bytes32 _marketTermsId\n ) external view returns (PaymentCycleType) {\n return PaymentCycleType.Seconds;\n }\n\n function getPaymentCycleDurationForTerms(\n bytes32 _marketTermsId\n ) external view returns (uint32) {\n return 3000;\n }\n\n function createMarket(\n address _initialOwner,\n bool _requireLenderAttestation,\n bool _requireBorrowerAttestation,\n string calldata _uri,\n MarketplaceTerms memory _marketTermsParams\n ) external returns (uint256 marketId_, bytes32 marketTerms_) {}\n\n function closeMarket(uint256 _marketId) public {}\n\n function mock_setGlobalMarketsClosed(bool closed) public {\n globalMarketsClosed = closed;\n }\n\n function mock_setBorrowerIsVerified(bool verified) public {\n globalBorrowerIsVerified = verified;\n }\n\n function mock_setLenderIsVerified(bool verified) public {\n globalLenderIsVerified = verified;\n }\n}\n" + }, + "contracts/mock/TellerV2SolMock.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.8.0 <0.9.0;\n\nimport \"../TellerV2.sol\";\nimport \"../interfaces/ITellerV2.sol\";\nimport \"../interfaces/IProtocolFee.sol\";\nimport \"../TellerV2Context.sol\";\nimport { Collateral } from \"../interfaces/escrow/ICollateralEscrowV1.sol\";\nimport { LoanDetails, Payment, BidState } from \"../TellerV2Storage.sol\";\n\n/*\nThis is only used for sol test so its named specifically to avoid being used for the typescript tests.\n*/\ncontract TellerV2SolMock is ITellerV2, IProtocolFee, TellerV2Storage {\n address public collateralManagerMock;\n address public trustedForwarder;\n address public approvedForwarder;\n\n PaymentCycleType globalBidPaymentCycleType = PaymentCycleType.Seconds;\n uint32 globalBidPaymentCycleDuration = 3000;\n\n Bid mockBid;\n\n function setMarketRegistry(address _marketRegistry) public {\n marketRegistry = IMarketRegistry_V2(_marketRegistry);\n }\n\n function getMarketRegistry() external view returns (IMarketRegistry) {\n return marketRegistry;\n }\n\n function protocolFee() external view returns (uint16) {\n return 100;\n }\n\n function submitBid(\n address _lendingToken,\n uint256 _marketId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata,\n address _receiver\n ) public returns (uint256 bidId_) {\n bidId_ = nextBidId;\n\n Bid storage bid = bids[bidId_];\n bid.borrower = msg.sender;\n bid.receiver = _receiver != address(0) ? _receiver : bid.borrower;\n bid.marketplaceId = _marketId;\n bid.loanDetails.lendingToken = IERC20(_lendingToken);\n bid.loanDetails.principal = _principal;\n bid.loanDetails.loanDuration = _duration;\n bid.loanDetails.timestamp = uint32(block.timestamp);\n\n /*(bid.terms.paymentCycle, bidPaymentCycleType[bidId]) = marketRegistry\n .getPaymentCycle(_marketId);*/\n\n bid.terms.APR = _APR;\n\n nextBidId++;\n }\n\n function submitBid(\n address _lendingToken,\n uint256 _marketplaceId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata _metadataURI,\n address _receiver,\n Collateral[] calldata _collateralInfo\n ) public returns (uint256 bidId_) {\n submitBid(\n _lendingToken,\n _marketplaceId,\n _principal,\n _duration,\n _APR,\n _metadataURI,\n _receiver\n );\n }\n\n function repayLoanMinimum(uint256 _bidId) external {}\n\n function repayLoanFull(uint256 _bidId) external {\n Bid storage bid = bids[_bidId];\n\n (uint256 owedPrincipal, , uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bids[_bidId],\n block.timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n\n uint256 _amount = owedPrincipal + interest;\n\n IERC20(bid.loanDetails.lendingToken).transferFrom(\n msg.sender,\n address(this),\n _amount\n );\n }\n\n function repayLoan(uint256 _bidId, uint256 _amount) public {\n Bid storage bid = bids[_bidId];\n\n IERC20(bid.loanDetails.lendingToken).transferFrom(\n msg.sender,\n address(this),\n _amount\n );\n }\n\n /*\n * @notice Calculates the minimum payment amount due for a loan.\n * @param _bidId The id of the loan bid to get the payment amount for.\n */\n function calculateAmountDue(\n uint256 _bidId,\n uint256 _timestamp\n ) public view returns (Payment memory due) {\n if (bids[_bidId].state != BidState.ACCEPTED) return due;\n\n (, uint256 duePrincipal, uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bids[_bidId],\n _timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n due.principal = duePrincipal;\n due.interest = interest;\n }\n\n function calculateAmountOwed(\n uint256 _bidId,\n uint256 _timestamp\n ) public view returns (Payment memory due) {\n if (bids[_bidId].state != BidState.ACCEPTED) return due;\n\n (uint256 owedPrincipal, , uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bids[_bidId],\n _timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n due.principal = owedPrincipal;\n due.interest = interest;\n }\n\n function lenderAcceptBid(\n uint256 _bidId\n )\n public\n returns (\n uint256 amountToProtocol,\n uint256 amountToMarketplace,\n uint256 amountToBorrower\n )\n {\n Bid storage bid = bids[_bidId];\n\n bid.lender = msg.sender;\n\n bid.state = BidState.ACCEPTED;\n\n //send tokens to caller\n IERC20(bid.loanDetails.lendingToken).transferFrom(\n bid.lender,\n bid.receiver,\n bid.loanDetails.principal\n );\n //for the reciever\n\n return (0, bid.loanDetails.principal, 0);\n }\n\n function getBidState(\n uint256 _bidId\n ) public view virtual returns (BidState) {\n return bids[_bidId].state;\n }\n\n function setCollateralManagerSuper(address _collateralManager) public {\n collateralManagerMock = address(_collateralManager);\n }\n\n function getCollateralManagerForBid(\n uint256 _bidId\n ) public view override returns (ICollateralManager) {\n return _getCollateralManagerForBid(_bidId);\n }\n\n function _getCollateralManagerForBid(\n uint256 _bidId\n ) internal view returns (ICollateralManager) {\n return ICollateralManager(collateralManagerMock);\n }\n\n function setMockBid(uint256 _bidId, Bid calldata bid) public {\n bids[_bidId] = bid;\n }\n\n function setTrustedMarketForwarder(\n uint256 _marketId,\n address _forwarder\n ) external {\n trustedForwarder = _forwarder;\n }\n\n function approveMarketForwarder(\n uint256 _marketId,\n address _forwarder\n ) external {\n approvedForwarder = _forwarder;\n }\n\n function getLoanDetails(\n uint256 _bidId\n ) public view returns (LoanDetails memory) {\n return bids[_bidId].loanDetails;\n }\n\n function getBorrowerActiveLoanIds(\n address _borrower\n ) public view returns (uint256[] memory) {}\n\n function isLoanDefaulted(\n uint256 _bidId\n ) public view virtual returns (bool) {}\n\n function isLoanLiquidateable(\n uint256 _bidId\n ) public view virtual returns (bool) {}\n\n function isPaymentLate(uint256 _bidId) public view returns (bool) {}\n\n function getLoanBorrower(\n uint256 _bidId\n ) external view virtual returns (address borrower_) {\n borrower_ = bids[_bidId].borrower;\n }\n\n function getLoanLender(\n uint256 _bidId\n ) external view virtual returns (address lender_) {\n lender_ = bids[_bidId].lender;\n }\n\n function getLoanMarketId(\n uint256 _bidId\n ) external view returns (uint256 _marketId) {\n _marketId = bids[_bidId].marketplaceId;\n }\n\n function getLoanLendingToken(\n uint256 _bidId\n ) external view returns (address token_) {\n token_ = address(bids[_bidId].loanDetails.lendingToken);\n }\n\n function getLoanSummary(\n uint256 _bidId\n )\n external\n view\n returns (\n address borrower,\n address lender,\n uint256 marketId,\n address principalTokenAddress,\n uint256 principalAmount,\n uint32 acceptedTimestamp,\n uint32 lastRepaidTimestamp,\n BidState bidState\n )\n {\n Bid storage bid = bids[_bidId];\n\n borrower = bid.borrower;\n lender = bid.lender;\n marketId = bid.marketplaceId;\n principalTokenAddress = address(bid.loanDetails.lendingToken);\n principalAmount = bid.loanDetails.principal;\n acceptedTimestamp = bid.loanDetails.acceptedTimestamp;\n lastRepaidTimestamp = bid.loanDetails.lastRepaidTimestamp;\n bidState = bid.state;\n }\n\n function setLastRepaidTimestamp(uint256 _bidId, uint32 _timestamp) public {\n bids[_bidId].loanDetails.lastRepaidTimestamp = _timestamp;\n }\n\n function _getBidPaymentCycleType(\n uint256 _bidId\n ) internal view returns (PaymentCycleType) {\n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n if (bidTermsId != bytes32(0)) {\n return marketRegistry.getPaymentCycleTypeForTerms(bidTermsId);\n }\n\n return globalBidPaymentCycleType;\n }\n\n function _getBidPaymentCycleDuration(\n uint256 _bidId\n ) internal view returns (uint32) {\n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n if (bidTermsId != bytes32(0)) {\n return marketRegistry.getPaymentCycleDurationForTerms(bidTermsId);\n }\n\n Bid storage bid = bids[_bidId];\n\n return globalBidPaymentCycleDuration;\n }\n\n function collateralManager() external view returns (address) {\n return collateralManagerMock;\n }\n}\n" + }, + "contracts/ProtocolFee.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\ncontract ProtocolFee is OwnableUpgradeable {\n // Protocol fee set for loan processing.\n uint16 private _protocolFee;\n\n /**\n * @notice This event is emitted when the protocol fee has been updated.\n * @param newFee The new protocol fee set.\n * @param oldFee The previously set protocol fee.\n */\n event ProtocolFeeSet(uint16 newFee, uint16 oldFee);\n\n /**\n * @notice Initialized the protocol fee.\n * @param initFee The initial protocol fee to be set on the protocol.\n */\n function __ProtocolFee_init(uint16 initFee) internal onlyInitializing {\n __Ownable_init();\n __ProtocolFee_init_unchained(initFee);\n }\n\n function __ProtocolFee_init_unchained(uint16 initFee)\n internal\n onlyInitializing\n {\n setProtocolFee(initFee);\n }\n\n /**\n * @notice Returns the current protocol fee.\n */\n function protocolFee() public view virtual returns (uint16) {\n return _protocolFee;\n }\n\n /**\n * @notice Lets the DAO/owner of the protocol to set a new protocol fee.\n * @param newFee The new protocol fee to be set.\n */\n function setProtocolFee(uint16 newFee) public virtual onlyOwner {\n // Skip if the fee is the same\n if (newFee == _protocolFee) return;\n\n uint16 oldFee = _protocolFee;\n _protocolFee = newFee;\n emit ProtocolFeeSet(newFee, oldFee);\n }\n}\n" + }, + "contracts/ReputationManager.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0 <0.9.0;\n\n// Interfaces\nimport \"./interfaces/IReputationManager.sol\";\nimport \"./interfaces/ITellerV2.sol\";\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\n\n// Libraries\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\ncontract ReputationManager is IReputationManager, Initializable {\n using EnumerableSet for EnumerableSet.UintSet;\n\n bytes32 public constant CONTROLLER = keccak256(\"CONTROLLER\");\n\n ITellerV2 public tellerV2;\n mapping(address => EnumerableSet.UintSet) private _delinquencies;\n mapping(address => EnumerableSet.UintSet) private _defaults;\n mapping(address => EnumerableSet.UintSet) private _currentDelinquencies;\n mapping(address => EnumerableSet.UintSet) private _currentDefaults;\n\n event MarkAdded(\n address indexed account,\n RepMark indexed repMark,\n uint256 bidId\n );\n event MarkRemoved(\n address indexed account,\n RepMark indexed repMark,\n uint256 bidId\n );\n\n /**\n * @notice Initializes the proxy.\n */\n function initialize(address _tellerV2) external initializer {\n tellerV2 = ITellerV2(_tellerV2);\n }\n\n function getDelinquentLoanIds(address _account)\n public\n view\n override\n returns (uint256[] memory)\n {\n //updateAccountReputation(_account);\n return _delinquencies[_account].values();\n }\n\n function getDefaultedLoanIds(address _account)\n public\n view\n override\n returns (uint256[] memory)\n {\n //updateAccountReputation(_account);\n return _defaults[_account].values();\n }\n\n function getCurrentDelinquentLoanIds(address _account)\n public\n view\n override\n returns (uint256[] memory)\n {\n //updateAccountReputation(_account);\n return _currentDelinquencies[_account].values();\n }\n\n function getCurrentDefaultLoanIds(address _account)\n public\n view\n override\n returns (uint256[] memory)\n {\n //updateAccountReputation(_account);\n return _currentDefaults[_account].values();\n }\n\n /*function updateAccountReputation(address _account) public override {\n uint256[] memory activeBidIds = tellerV2.getBorrowerActiveLoanIds(\n _account\n );\n for (uint256 i; i < activeBidIds.length; i++) {\n _applyReputation(_account, activeBidIds[i]);\n }\n }*/\n\n function updateAccountReputation(address _account, uint256 _bidId)\n public\n override\n returns (RepMark)\n {\n return _applyReputation(_account, _bidId);\n }\n\n function _applyReputation(address _account, uint256 _bidId)\n internal\n returns (RepMark mark_)\n {\n mark_ = RepMark.Good;\n\n if (tellerV2.isLoanDefaulted(_bidId)) {\n mark_ = RepMark.Default;\n\n // Remove delinquent status\n _removeMark(_account, _bidId, RepMark.Delinquent);\n } else if (tellerV2.isPaymentLate(_bidId)) {\n mark_ = RepMark.Delinquent;\n }\n\n // Mark status if not \"Good\"\n if (mark_ != RepMark.Good) {\n _addMark(_account, _bidId, mark_);\n }\n }\n\n function _addMark(address _account, uint256 _bidId, RepMark _mark)\n internal\n {\n if (_mark == RepMark.Delinquent) {\n _delinquencies[_account].add(_bidId);\n _currentDelinquencies[_account].add(_bidId);\n } else if (_mark == RepMark.Default) {\n _defaults[_account].add(_bidId);\n _currentDefaults[_account].add(_bidId);\n }\n\n emit MarkAdded(_account, _mark, _bidId);\n }\n\n function _removeMark(address _account, uint256 _bidId, RepMark _mark)\n internal\n {\n if (_mark == RepMark.Delinquent) {\n _currentDelinquencies[_account].remove(_bidId);\n } else if (_mark == RepMark.Default) {\n _currentDefaults[_account].remove(_bidId);\n }\n\n emit MarkRemoved(_account, _mark, _bidId);\n }\n}\n" + }, + "contracts/TellerV2.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// Contracts\nimport \"./ProtocolFee.sol\";\nimport \"./TellerV2Storage.sol\";\nimport \"./TellerV2Context.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol\";\n\nimport \"./interfaces/ICollateralManager.sol\";\n\n// Interfaces\nimport \"./interfaces/IMarketRegistry_V2.sol\";\nimport \"./interfaces/IReputationManager.sol\";\nimport \"./interfaces/ITellerV2.sol\";\nimport { Collateral } from \"./interfaces/escrow/ICollateralEscrowV1.sol\";\nimport \"./interfaces/IEscrowVault.sol\";\n\n// Libraries\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"./libraries/NumbersLib.sol\";\n\nimport { V2Calculations, PaymentCycleType } from \"./libraries/V2Calculations.sol\";\n \n\n/* Errors */\n/**\n * @notice This error is reverted when the action isn't allowed\n * @param bidId The id of the bid.\n * @param action The action string (i.e: 'repayLoan', 'cancelBid', 'etc)\n * @param message The message string to return to the user explaining why the tx was reverted\n */\nerror ActionNotAllowed(uint256 bidId, string action, string message);\n\n/**\n * @notice This error is reverted when repayment amount is less than the required minimum\n * @param bidId The id of the bid the borrower is attempting to repay.\n * @param payment The payment made by the borrower\n * @param minimumOwed The minimum owed value\n */\nerror PaymentNotMinimum(uint256 bidId, uint256 payment, uint256 minimumOwed);\n\ncontract TellerV2 is\n ITellerV2,\n OwnableUpgradeable,\n ProtocolFee,\n PausableUpgradeable,\n TellerV2Storage,\n TellerV2Context\n{\n using Address for address;\n using SafeERC20 for IERC20;\n using NumbersLib for uint256;\n using EnumerableSet for EnumerableSet.AddressSet;\n using EnumerableSet for EnumerableSet.UintSet;\n\n //the first 20 bytes of keccak256(\"lender manager\")\n address constant USING_LENDER_MANAGER =\n 0x84D409EeD89F6558fE3646397146232665788bF8;\n\n /** Events */\n\n /**\n * @notice This event is emitted when a new bid is submitted.\n * @param bidId The id of the bid submitted.\n * @param borrower The address of the bid borrower.\n * @param metadataURI URI for additional bid information as part of loan bid.\n */\n event SubmittedBid(\n uint256 indexed bidId,\n address indexed borrower,\n address receiver,\n bytes32 indexed metadataURI\n );\n\n /**\n * @notice This event is emitted when a bid has been accepted by a lender.\n * @param bidId The id of the bid accepted.\n * @param lender The address of the accepted bid lender.\n */\n event AcceptedBid(uint256 indexed bidId, address indexed lender);\n\n /**\n * @notice This event is emitted when a previously submitted bid has been cancelled.\n * @param bidId The id of the cancelled bid.\n */\n event CancelledBid(uint256 indexed bidId);\n\n /**\n * @notice This event is emitted when market owner has cancelled a pending bid in their market.\n * @param bidId The id of the bid funded.\n *\n * Note: The `CancelledBid` event will also be emitted.\n */\n event MarketOwnerCancelledBid(uint256 indexed bidId);\n\n /**\n * @notice This event is emitted when a payment is made towards an active loan.\n * @param bidId The id of the bid/loan to which the payment was made.\n */\n event LoanRepayment(uint256 indexed bidId);\n\n /**\n * @notice This event is emitted when a loan has been fully repaid.\n * @param bidId The id of the bid/loan which was repaid.\n */\n event LoanRepaid(uint256 indexed bidId);\n\n /**\n * @notice This event is emitted when a loan has been fully repaid.\n * @param bidId The id of the bid/loan which was repaid.\n */\n event LoanLiquidated(uint256 indexed bidId, address indexed liquidator);\n\n /**\n * @notice This event is emitted when a loan has been closed.\n * @param bidId The id of the bid/loan which was closed.\n */\n event LoanClosed(uint256 indexed bidId);\n\n /**\n * @notice This event is emitted when a fee has been paid related to a bid.\n * @param bidId The id of the bid.\n * @param feeType The name of the fee being paid.\n * @param amount The amount of the fee being paid.\n */\n event FeePaid(\n uint256 indexed bidId,\n string indexed feeType,\n uint256 indexed amount\n );\n\n event SetBidMarketTerms(\n uint256 indexed bidId,\n bytes32 indexed marketTermsId \n );\n\n /** Modifiers */\n\n /**\n * @notice This modifier is used to check if the state of a bid is pending, before running an action.\n * @param _bidId The id of the bid to check the state for.\n * @param _action The desired action to run on the bid.\n */\n modifier pendingBid(uint256 _bidId, string memory _action) {\n if (bids[_bidId].state != BidState.PENDING) {\n revert ActionNotAllowed(_bidId, _action, \"Bid must be pending\");\n }\n\n _;\n }\n\n /**\n * @notice This modifier is used to check if the state of a loan has been accepted, before running an action.\n * @param _bidId The id of the bid to check the state for.\n * @param _action The desired action to run on the bid.\n */\n modifier acceptedLoan(uint256 _bidId, string memory _action) {\n if (bids[_bidId].state != BidState.ACCEPTED) {\n revert ActionNotAllowed(_bidId, _action, \"Loan must be accepted\");\n }\n\n _;\n }\n\n /** Constant Variables **/\n\n uint32 public constant LIQUIDATION_DELAY = 86400; //ONE DAY IN SECONDS\n\n /** Constructor **/\n\n constructor(address trustedForwarder) TellerV2Context(trustedForwarder) {}\n\n /** External Functions **/\n\n /**\n * @notice Initializes the proxy.\n * @param _protocolFee The fee collected by the protocol for loan processing.\n * @param _marketRegistry The address of the market registry contract for the protocol.\n * @param _reputationManager The address of the reputation manager contract\n * @param _lenderManager The address of the lender manager contract for loans on the protocol.\n * @param _escrowVault the address of the escrow vault contract for push pull\n * @param _collateralManagerV2 the address of the collateral manager V2 contract.\n */\n function initialize(\n uint16 _protocolFee,\n address _marketRegistry,\n address _reputationManager,\n //address _lenderCommitmentForwarder,\n //address _collateralManagerV1,\n address _lenderManager,\n address _escrowVault,\n address _collateralManagerV2\n ) external initializer {\n __ProtocolFee_init(_protocolFee);\n\n __Pausable_init();\n\n //no longer needed in storage\n lenderCommitmentForwarder = address(0);\n\n require(\n _marketRegistry.isContract(),\n \"MarketRegistry must be a contract\"\n );\n marketRegistry = IMarketRegistry_V2(_marketRegistry);\n\n require(\n _reputationManager.isContract(),\n \"ReputationManager must be a contract\"\n );\n reputationManager = IReputationManager(_reputationManager);\n\n _setLenderManager(_lenderManager);\n _setEscrowVault(_escrowVault);\n _setCollateralManagerV2(_collateralManagerV2);\n }\n\n function setCollateralManagerV2(\n address _collateralManagerV2\n ) external reinitializer(10) {\n require(address(_collateralManagerV2) == address(0));\n _setCollateralManagerV2(_collateralManagerV2);\n }\n\n function _setEscrowVault(address _escrowVault) internal onlyInitializing {\n require(_escrowVault.isContract(), \"EscrowVault must be a contract\");\n escrowVault = IEscrowVault(_escrowVault);\n }\n\n function _setLenderManager(\n address _lenderManager\n ) internal onlyInitializing {\n require(\n _lenderManager.isContract(),\n \"LenderManager must be a contract\"\n );\n lenderManager = ILenderManager(_lenderManager);\n }\n\n function _setCollateralManagerV2(\n address _collateralManagerV2\n ) internal onlyInitializing {\n require(\n _collateralManagerV2.isContract(),\n \"CollateralManagerV2 must be a contract\"\n );\n collateralManagerV2 = ICollateralManagerV2(_collateralManagerV2);\n }\n\n /**\n * @notice Gets the metadataURI for a bidId.\n * @param _bidId The id of the bid to return the metadataURI for\n * @return metadataURI_ The metadataURI for the bid, as a string.\n */\n function getMetadataURI(\n uint256 _bidId\n ) public view returns (string memory metadataURI_) {\n // Check uri mapping first\n metadataURI_ = uris[_bidId];\n // If the URI is not present in the mapping\n if (\n keccak256(abi.encodePacked(metadataURI_)) ==\n 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 // hardcoded constant of keccak256('')\n ) {\n // Return deprecated bytes32 uri as a string\n uint256 convertedURI = uint256(bids[_bidId]._metadataURI);\n metadataURI_ = StringsUpgradeable.toHexString(convertedURI, 32);\n }\n }\n\n /**\n * @notice Function for a borrower to create a bid for a loan without Collateral.\n * @param _lendingToken The lending token asset requested to be borrowed.\n * @param _marketplaceId The unique id of the marketplace for the bid.\n * @param _principal The principal amount of the loan bid.\n * @param _duration The recurrent length of time before which a payment is due.\n * @param _APR The proposed interest rate for the loan bid.\n * @param _metadataURI The URI for additional borrower loan information as part of loan bid.\n * @param _receiver The address where the loan amount will be sent to.\n */\n function submitBid(\n address _lendingToken,\n uint256 _marketplaceId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata _metadataURI,\n address _receiver\n ) public override whenNotPaused returns (uint256 bidId_) {\n bidId_ = _submitBid(\n _lendingToken,\n _marketplaceId,\n _principal,\n _duration,\n _APR,\n _metadataURI,\n _receiver\n );\n }\n\n /**\n * @notice Function for a borrower to create a bid for a loan with Collateral.\n * @param _lendingToken The lending token asset requested to be borrowed.\n * @param _marketplaceId The unique id of the marketplace for the bid.\n * @param _principal The principal amount of the loan bid.\n * @param _duration The recurrent length of time before which a payment is due.\n * @param _APR The proposed interest rate for the loan bid.\n * @param _metadataURI The URI for additional borrower loan information as part of loan bid.\n * @param _receiver The address where the loan amount will be sent to.\n * @param _collateralInfo Additional information about the collateral asset.\n */\n function submitBid(\n address _lendingToken,\n uint256 _marketplaceId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata _metadataURI,\n address _receiver,\n Collateral[] calldata _collateralInfo\n ) public override whenNotPaused returns (uint256 bidId_) {\n bidId_ = _submitBid(\n _lendingToken,\n _marketplaceId,\n _principal,\n _duration,\n _APR,\n _metadataURI,\n _receiver\n );\n\n bool validation = collateralManagerV2.commitCollateral(\n bidId_,\n _collateralInfo\n );\n\n require(\n validation == true,\n \"Collateral balance could not be validated\"\n );\n }\n\n function _submitBid(\n address _lendingToken,\n uint256 _marketplaceId,\n uint256 _principal,\n uint32 _duration,\n uint16 _APR,\n string calldata _metadataURI,\n address _receiver\n ) internal virtual returns (uint256 bidId_) {\n address sender = _msgSenderForMarket(_marketplaceId);\n\n {\n (bool isVerified, ) = marketRegistry.isVerifiedBorrower(\n _marketplaceId,\n sender\n );\n\n require(isVerified, \"Not verified borrower\");\n }\n\n require(\n marketRegistry.isMarketOpen(_marketplaceId),\n \"Market is not open\"\n );\n\n // Set response bid ID.\n bidId_ = nextBidId;\n\n // Create and store our bid into the mapping\n Bid storage bid = bids[nextBidId];\n bid.borrower = sender;\n bid.receiver = _receiver != address(0) ? _receiver : bid.borrower;\n bid.marketplaceId = _marketplaceId;\n bid.loanDetails.lendingToken = IERC20(_lendingToken);\n bid.loanDetails.principal = _principal;\n bid.loanDetails.loanDuration = _duration;\n bid.loanDetails.timestamp = uint32(block.timestamp);\n\n //make this new bid use the most recent version of collateral manager\n collateralManagerForBid[bidId_] = address(collateralManagerV2);\n\n // Set payment cycle type based on market setting (custom or monthly)\n\n bidMarketTermsId[bidId_] = marketRegistry.getCurrentTermsForMarket(\n _marketplaceId\n ); \n\n require(bidMarketTermsId[bidId_] != bytes32(0), \"Market does not have assigned terms.\");\n\n (\n uint32 paymentCycleDuration,\n PaymentCycleType paymentCycleType,\n PaymentType paymentType,\n ,\n\n ) = marketRegistry.getMarketTermsForLending(bidMarketTermsId[bidId_]);\n \n\n bid.terms.APR = _APR;\n\n bid.terms.paymentCycleAmount = V2Calculations\n .calculatePaymentCycleAmount(\n paymentType,\n paymentCycleType,\n _principal,\n _duration,\n paymentCycleDuration,\n _APR\n );\n\n //uris[bidId] = _metadataURI;\n bid.state = BidState.PENDING;\n\n emit SubmittedBid(\n bidId_,\n bid.borrower,\n bid.receiver,\n keccak256(abi.encodePacked(_metadataURI))\n );\n\n emit SetBidMarketTerms(\n bidId_,\n bidMarketTermsId[bidId_]\n );\n\n // Store bid inside borrower bids mapping\n //borrowerBids[bid.borrower].push(bidId);\n\n // Increment bid id counter\n nextBidId++;\n }\n\n /**\n * @notice Function for a borrower to cancel their pending bid.\n * @param _bidId The id of the bid to cancel.\n */\n function cancelBid(uint256 _bidId) external {\n if (\n _msgSenderForMarket(bids[_bidId].marketplaceId) !=\n bids[_bidId].borrower\n ) {\n revert ActionNotAllowed({\n bidId: _bidId,\n action: \"cancelBid\",\n message: \"Only the bid owner can cancel!\"\n });\n }\n _cancelBid(_bidId);\n }\n\n /**\n * @notice Function for a market owner to cancel a bid in the market.\n * @param _bidId The id of the bid to cancel.\n */\n function marketOwnerCancelBid(uint256 _bidId) external {\n if (\n _msgSender() !=\n marketRegistry.getMarketOwner(bids[_bidId].marketplaceId)\n ) {\n revert ActionNotAllowed({\n bidId: _bidId,\n action: \"marketOwnerCancelBid\",\n message: \"Only the market owner can cancel!\"\n });\n }\n _cancelBid(_bidId);\n emit MarketOwnerCancelledBid(_bidId);\n }\n\n /**\n * @notice Function for users to cancel a bid.\n * @param _bidId The id of the bid to be cancelled.\n */\n function _cancelBid(\n uint256 _bidId\n ) internal virtual pendingBid(_bidId, \"cancelBid\") {\n // Set the bid state to CANCELLED\n bids[_bidId].state = BidState.CANCELLED;\n\n // Emit CancelledBid event\n emit CancelledBid(_bidId);\n }\n\n /**\n * @notice Function for a lender to accept a proposed loan bid.\n * @param _bidId The id of the loan bid to accept.\n */\n function lenderAcceptBid(\n uint256 _bidId\n )\n external\n override\n pendingBid(_bidId, \"lenderAcceptBid\")\n whenNotPaused\n returns (\n uint256 amountToProtocol,\n uint256 amountToMarketplace,\n uint256 amountToBorrower\n )\n {\n // Retrieve bid\n Bid storage bid = bids[_bidId];\n\n \n address sender = _msgSenderForMarket(bid.marketplaceId);\n \n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n \n //bytes32 currentMarketplaceTermsId = marketRegistry.getCurrentTermsForMarket(_marketplaceId);\n\n (bool isVerified, ) = marketRegistry.isVerifiedLender(\n bid.marketplaceId,\n sender\n );\n\n require(isVerified, \"Not verified lender\");\n\n require(\n !marketRegistry.isMarketClosed(bid.marketplaceId),\n \"Market is closed\"\n );\n\n require(!isLoanExpired(_bidId), \"Bid has expired\");\n\n // Set timestamp\n bid.loanDetails.acceptedTimestamp = uint32(block.timestamp);\n bid.loanDetails.lastRepaidTimestamp = uint32(block.timestamp);\n\n // Mark borrower's request as accepted\n bid.state = BidState.ACCEPTED;\n\n // Declare the bid acceptor as the lender of the bid\n bid.lender = sender;\n\n // Tell the collateral manager to deploy the escrow and pull funds from the borrower if applicable\n if (collateralManagerForBid[_bidId] == address(0)) {\n collateralManagerV1.deployAndDeposit(_bidId);\n } else {\n collateralManagerV2.depositCollateral(_bidId);\n }\n\n (address marketFeeRecipient, uint16 marketFee) = marketRegistry\n .getMarketFeeTerms(bidTermsId);\n \n \n\n // Transfer funds to borrower from the lender\n amountToProtocol = bid.loanDetails.principal.percent(protocolFee());\n amountToMarketplace = bid.loanDetails.principal.percent(marketFee);\n amountToBorrower =\n bid.loanDetails.principal -\n amountToProtocol -\n amountToMarketplace;\n\n //transfer fee to protocol\n if (amountToProtocol > 0) {\n bid.loanDetails.lendingToken.safeTransferFrom(\n sender,\n owner(),\n amountToProtocol\n );\n }\n\n //transfer fee to marketplace\n if (amountToMarketplace > 0) {\n bid.loanDetails.lendingToken.safeTransferFrom(\n sender,\n marketFeeRecipient,\n amountToMarketplace\n );\n }\n\n //transfer funds to borrower\n if (amountToBorrower > 0) {\n bid.loanDetails.lendingToken.safeTransferFrom(\n sender,\n bid.receiver,\n amountToBorrower\n );\n }\n\n // Record volume filled by lenders\n lenderVolumeFilled[address(bid.loanDetails.lendingToken)][sender] += bid\n .loanDetails\n .principal;\n totalVolumeFilled[address(bid.loanDetails.lendingToken)] += bid\n .loanDetails\n .principal;\n\n // Add borrower's active bid\n //_borrowerBidsActive[bid.borrower].add(_bidId);\n\n // Emit AcceptedBid\n emit AcceptedBid(_bidId, sender);\n\n emit FeePaid(_bidId, \"protocol\", amountToProtocol);\n emit FeePaid(_bidId, \"marketplace\", amountToMarketplace);\n }\n\n function claimLoanNFT(\n uint256 _bidId\n ) external acceptedLoan(_bidId, \"claimLoanNFT\") whenNotPaused {\n // Retrieve bid\n Bid storage bid = bids[_bidId];\n\n address sender = _msgSenderForMarket(bid.marketplaceId);\n require(sender == bid.lender, \"only lender can claim NFT\");\n\n // set lender address to the lender manager so we know to check the owner of the NFT for the true lender\n bid.lender = address(USING_LENDER_MANAGER);\n\n // mint an NFT with the lender manager\n lenderManager.registerLoan(_bidId, sender);\n }\n\n /**\n * @notice Function for users to make the minimum amount due for an active loan.\n * @param _bidId The id of the loan to make the payment towards.\n */\n function repayLoanMinimum(\n uint256 _bidId\n ) external acceptedLoan(_bidId, \"repayLoan\") {\n (\n uint256 owedPrincipal,\n uint256 duePrincipal,\n uint256 interest\n ) = V2Calculations.calculateAmountOwed(\n bids[_bidId],\n block.timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n _repayLoan(\n _bidId,\n Payment({ principal: duePrincipal, interest: interest }),\n owedPrincipal + interest,\n true\n );\n }\n\n /**\n * @notice Function for users to repay an active loan in full.\n * @param _bidId The id of the loan to make the payment towards.\n */\n function repayLoanFull(\n uint256 _bidId\n ) external acceptedLoan(_bidId, \"repayLoan\") {\n _repayLoanFull(_bidId, true);\n }\n\n // function that the borrower (ideally) sends to repay the loan\n /**\n * @notice Function for users to make a payment towards an active loan.\n * @param _bidId The id of the loan to make the payment towards.\n * @param _amount The amount of the payment.\n */\n function repayLoan(\n uint256 _bidId,\n uint256 _amount\n ) external acceptedLoan(_bidId, \"repayLoan\") {\n _repayLoanAtleastMinimum(_bidId, _amount, true);\n }\n\n /**\n * @notice Function for users to repay an active loan in full.\n * @param _bidId The id of the loan to make the payment towards.\n */\n function repayLoanFullWithoutCollateralWithdraw(\n uint256 _bidId\n ) external acceptedLoan(_bidId, \"repayLoan\") {\n _repayLoanFull(_bidId, false);\n }\n\n function repayLoanWithoutCollateralWithdraw(\n uint256 _bidId,\n uint256 _amount\n ) external acceptedLoan(_bidId, \"repayLoan\") {\n _repayLoanAtleastMinimum(_bidId, _amount, false);\n }\n\n function _repayLoanFull(uint256 _bidId, bool withdrawCollateral) internal {\n \n (uint256 owedPrincipal, , uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bids[_bidId],\n block.timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n _repayLoan(\n _bidId,\n Payment({ principal: owedPrincipal, interest: interest }),\n owedPrincipal + interest,\n withdrawCollateral\n );\n }\n\n function _repayLoanAtleastMinimum(\n uint256 _bidId,\n uint256 _amount,\n bool withdrawCollateral\n ) internal {\n (\n uint256 owedPrincipal,\n uint256 duePrincipal,\n uint256 interest\n ) = V2Calculations.calculateAmountOwed(\n bids[_bidId],\n block.timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n uint256 minimumOwed = duePrincipal + interest;\n\n // If amount is less than minimumOwed, we revert\n if (_amount < minimumOwed) {\n revert PaymentNotMinimum(_bidId, _amount, minimumOwed);\n }\n\n _repayLoan(\n _bidId,\n Payment({ principal: _amount - interest, interest: interest }),\n owedPrincipal + interest,\n withdrawCollateral\n );\n }\n\n /**\n * @notice Lets the DAO/owner of the protocol implement an emergency stop mechanism.\n */\n function pauseProtocol() public virtual onlyOwner whenNotPaused {\n _pause();\n }\n\n /**\n * @notice Lets the DAO/owner of the protocol undo a previously implemented emergency stop.\n */\n function unpauseProtocol() public virtual onlyOwner whenPaused {\n _unpause();\n }\n\n /**\n * @notice Function for lender to claim collateral for a defaulted loan. The only purpose of a CLOSED loan is to make collateral claimable by lender.\n * @param _bidId The id of the loan to set to CLOSED status.\n */\n function lenderCloseLoan(\n uint256 _bidId\n ) external acceptedLoan(_bidId, \"lenderClaimCollateral\") {\n require(isLoanDefaulted(_bidId), \"Loan must be defaulted.\");\n\n Bid storage bid = bids[_bidId];\n bid.state = BidState.CLOSED;\n\n //collateralManager.lenderClaimCollateral(_bidId);\n\n _getCollateralManagerForBid(_bidId).lenderClaimCollateral(_bidId);\n emit LoanClosed(_bidId);\n }\n\n /**\n * @notice Function for users to liquidate a defaulted loan.\n * @param _bidId The id of the loan to make the payment towards.\n */\n function liquidateLoanFull(\n uint256 _bidId\n ) external acceptedLoan(_bidId, \"liquidateLoan\") {\n require(isLoanLiquidateable(_bidId), \"Loan must be liquidateable.\");\n\n Bid storage bid = bids[_bidId];\n\n // change state here to prevent re-entrancy\n bid.state = BidState.LIQUIDATED;\n\n (uint256 owedPrincipal, , uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bid,\n block.timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n\n //this sets the state to 'repaid'\n _repayLoan(\n _bidId,\n Payment({ principal: owedPrincipal, interest: interest }),\n owedPrincipal + interest,\n false\n );\n\n // If loan is backed by collateral, withdraw and send to the liquidator\n address liquidator = _msgSenderForMarket(bid.marketplaceId);\n //collateralManager.liquidateCollateral(_bidId, liquidator);\n _getCollateralManagerForBid(_bidId).liquidateCollateral(\n _bidId,\n liquidator\n );\n\n emit LoanLiquidated(_bidId, liquidator);\n }\n\n /**\n * @notice Internal function to make a loan payment.\n * @dev Updates the bid's `status` to `PAID` only if it is not already marked as `LIQUIDATED`\n * @param _bidId The id of the loan to make the payment towards.\n * @param _payment The Payment struct with payments amounts towards principal and interest respectively.\n * @param _owedAmount The total amount owed on the loan.\n */\n function _repayLoan(\n uint256 _bidId,\n Payment memory _payment,\n uint256 _owedAmount,\n bool _shouldWithdrawCollateral\n ) internal virtual {\n Bid storage bid = bids[_bidId];\n uint256 paymentAmount = _payment.principal + _payment.interest;\n\n RepMark mark = reputationManager.updateAccountReputation(\n bid.borrower,\n _bidId\n );\n\n // Check if we are sending a payment or amount remaining\n if (paymentAmount >= _owedAmount) {\n paymentAmount = _owedAmount;\n\n if (bid.state != BidState.LIQUIDATED) {\n bid.state = BidState.PAID;\n }\n\n // Remove borrower's active bid\n //_borrowerBidsActive[bid.borrower].remove(_bidId);\n\n // If loan is is being liquidated and backed by collateral, withdraw and send to borrower\n if (_shouldWithdrawCollateral) {\n //collateralManager.withdraw(_bidId);\n\n _getCollateralManagerForBid(_bidId).withdraw(_bidId);\n }\n\n emit LoanRepaid(_bidId);\n } else {\n emit LoanRepayment(_bidId);\n }\n\n _sendOrEscrowFunds(_bidId, paymentAmount); //send or escrow the funds\n\n // update our mappings\n bid.loanDetails.totalRepaid.principal += _payment.principal;\n bid.loanDetails.totalRepaid.interest += _payment.interest;\n bid.loanDetails.lastRepaidTimestamp = uint32(block.timestamp);\n\n // If the loan is paid in full and has a mark, we should update the current reputation\n if (mark != RepMark.Good) {\n reputationManager.updateAccountReputation(bid.borrower, _bidId);\n }\n }\n\n function _sendOrEscrowFunds(\n uint256 _bidId,\n uint256 _paymentAmount\n ) internal {\n Bid storage bid = bids[_bidId];\n address lender = getLoanLender(_bidId);\n\n try\n //first try to pay directly\n //have to use transfer from (not safe transfer from) for try/catch statement\n //dont try to use any more than 100k gas for this xfer\n bid.loanDetails.lendingToken.transferFrom{ gas: 100000 }(\n _msgSenderForMarket(bid.marketplaceId),\n lender,\n _paymentAmount\n )\n {} catch {\n address sender = _msgSenderForMarket(bid.marketplaceId);\n\n uint256 balanceBefore = bid.loanDetails.lendingToken.balanceOf(\n address(this)\n );\n\n //if unable, pay to escrow\n bid.loanDetails.lendingToken.safeTransferFrom(\n sender,\n address(this),\n _paymentAmount\n );\n\n uint256 balanceAfter = bid.loanDetails.lendingToken.balanceOf(\n address(this)\n );\n\n //used for fee-on-send tokens\n uint256 paymentAmountReceived = balanceAfter - balanceBefore;\n\n bid.loanDetails.lendingToken.approve(\n address(escrowVault),\n paymentAmountReceived\n );\n\n IEscrowVault(escrowVault).deposit(\n lender,\n address(bid.loanDetails.lendingToken),\n paymentAmountReceived\n );\n }\n }\n\n /**\n * @notice Calculates the total amount owed for a loan bid at a specific timestamp.\n * @param _bidId The id of the loan bid to calculate the owed amount for.\n * @param _timestamp The timestamp at which to calculate the loan owed amount at.\n */\n function calculateAmountOwed(\n uint256 _bidId,\n uint256 _timestamp\n ) public view returns (Payment memory owed) {\n Bid storage bid = bids[_bidId];\n if (\n bid.state != BidState.ACCEPTED ||\n bid.loanDetails.acceptedTimestamp >= _timestamp\n ) return owed;\n\n (uint256 owedPrincipal, , uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bid,\n _timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n owed.principal = owedPrincipal;\n owed.interest = interest;\n }\n\n /**\n * @notice Calculates the minimum payment amount due for a loan at a specific timestamp.\n * @param _bidId The id of the loan bid to get the payment amount for.\n * @param _timestamp The timestamp at which to get the due payment at.\n */\n function calculateAmountDue(\n uint256 _bidId,\n uint256 _timestamp\n ) public view returns (Payment memory due) {\n Bid storage bid = bids[_bidId];\n if (\n bids[_bidId].state != BidState.ACCEPTED ||\n bid.loanDetails.acceptedTimestamp >= _timestamp\n ) return due;\n\n (, uint256 duePrincipal, uint256 interest) = V2Calculations\n .calculateAmountOwed(\n bid,\n _timestamp,\n _getBidPaymentCycleType(_bidId),\n _getBidPaymentCycleDuration(_bidId)\n );\n due.principal = duePrincipal;\n due.interest = interest;\n }\n\n /**\n * @notice Returns the next due date for a loan payment.\n * @param _bidId The id of the loan bid.\n */\n function calculateNextDueDate(\n uint256 _bidId\n ) public view returns (uint32 dueDate_) {\n Bid storage bid = bids[_bidId];\n if (bids[_bidId].state != BidState.ACCEPTED) return dueDate_;\n\n return\n V2Calculations.calculateNextDueDate(\n bid.loanDetails.acceptedTimestamp,\n _getBidPaymentCycleDuration(_bidId),\n bid.loanDetails.loanDuration,\n lastRepaidTimestamp(_bidId),\n _getBidPaymentCycleType(_bidId)\n );\n }\n\n /**\n * @notice Checks to see if a borrower is delinquent.\n * @param _bidId The id of the loan bid to check for.\n */\n function isPaymentLate(uint256 _bidId) public view override returns (bool) {\n if (bids[_bidId].state != BidState.ACCEPTED) return false;\n return uint32(block.timestamp) > calculateNextDueDate(_bidId);\n }\n\n /**\n * @notice Checks to see if a borrower is delinquent.\n * @param _bidId The id of the loan bid to check for.\n * @return bool True if the loan is defaulted.\n */\n function isLoanDefaulted(\n uint256 _bidId\n ) public view override returns (bool) {\n return _isLoanDefaulted(_bidId, 0);\n }\n\n /**\n * @notice Checks to see if a loan was delinquent for longer than liquidation delay.\n * @param _bidId The id of the loan bid to check for.\n * @return bool True if the loan is liquidateable.\n */\n function isLoanLiquidateable(\n uint256 _bidId\n ) public view override returns (bool) {\n return _isLoanDefaulted(_bidId, LIQUIDATION_DELAY);\n }\n\n /**\n * @notice Checks to see if a borrower is delinquent.\n * @param _bidId The id of the loan bid to check for.\n * @param _additionalDelay Amount of additional seconds after a loan defaulted to allow a liquidation.\n * @return bool True if the loan is liquidateable.\n */\n function _isLoanDefaulted(\n uint256 _bidId,\n uint32 _additionalDelay\n ) internal view returns (bool) {\n Bid storage bid = bids[_bidId];\n\n // Make sure loan cannot be liquidated if it is not active\n if (bid.state != BidState.ACCEPTED) return false;\n\n uint32 defaultDuration = _getBidDefaultDuration(_bidId);\n\n if (defaultDuration == 0) return false;\n\n uint32 dueDate = calculateNextDueDate(_bidId);\n\n return\n uint32(block.timestamp) >\n dueDate + defaultDuration + _additionalDelay;\n }\n\n function getCollateralManagerForBid(\n uint256 _bidId\n ) public view virtual returns (ICollateralManager) {\n return _getCollateralManagerForBid(_bidId);\n }\n\n function _getCollateralManagerForBid(\n uint256 _bidId\n ) internal view virtual returns (ICollateralManager) {\n if (collateralManagerForBid[_bidId] == address(0)) {\n return ICollateralManager(collateralManagerV1);\n }\n return ICollateralManager(collateralManagerForBid[_bidId]);\n }\n\n //Returns the most modern implementation for the collateral manager\n function collateralManager() external view returns (address) {\n return address(collateralManagerV2);\n }\n\n function getBidState(\n uint256 _bidId\n ) external view override returns (BidState) {\n return bids[_bidId].state;\n }\n\n /* function getBorrowerActiveLoanIds(address _borrower)\n external\n view\n override\n returns (uint256[] memory)\n {\n return _borrowerBidsActive[_borrower].values();\n }\n\n function getBorrowerLoanIds(address _borrower)\n external\n view\n returns (uint256[] memory)\n {\n return borrowerBids[_borrower];\n }*/\n\n /**\n * @notice Checks to see if a pending loan has expired so it is no longer able to be accepted.\n * @param _bidId The id of the loan bid to check for.\n */\n function isLoanExpired(uint256 _bidId) public view returns (bool) {\n Bid storage bid = bids[_bidId];\n\n if (bid.state != BidState.PENDING) return false;\n if (_getBidExpirationTime(_bidId) == 0) return false;\n\n return (uint32(block.timestamp) >\n bid.loanDetails.timestamp + _getBidExpirationTime(_bidId));\n }\n\n function _getBidExpirationTime(\n uint256 _bidId\n ) internal view returns (uint32) {\n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n if (bidTermsId != bytes32(0)) {\n return marketRegistry.getBidExpirationTimeForTerms(bidTermsId);\n }\n\n return bidExpirationTime[_bidId];\n }\n\n function _getBidDefaultDuration(\n uint256 _bidId\n ) internal view returns (uint32) {\n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n if (bidTermsId != bytes32(0)) {\n return marketRegistry.getPaymentDefaultDurationForTerms(bidTermsId);\n }\n\n return bidDefaultDuration[_bidId];\n }\n\n function _getBidPaymentCycleType(\n uint256 _bidId\n ) internal view returns (PaymentCycleType) {\n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n if (bidTermsId != bytes32(0)) {\n return marketRegistry.getPaymentCycleTypeForTerms(bidTermsId);\n }\n\n return bidPaymentCycleType[_bidId];\n }\n \n\n\n function _getBidPaymentCycleDuration(\n uint256 _bidId\n ) internal view returns (uint32) {\n \n bytes32 bidTermsId = bidMarketTermsId[_bidId];\n \n\n if (bidTermsId != bytes32(0)) {\n \n return marketRegistry.getPaymentCycleDurationForTerms(bidTermsId);\n }\n\n Bid storage bid = bids[_bidId];\n \n\n return bid.terms.paymentCycle;\n }\n\n /**\n * @notice Returns the last repaid timestamp for a loan.\n * @param _bidId The id of the loan bid to get the timestamp for.\n */\n function lastRepaidTimestamp(uint256 _bidId) public view returns (uint32) {\n return V2Calculations.lastRepaidTimestamp(bids[_bidId]);\n }\n\n /**\n * @notice Returns the borrower address for a given bid.\n * @param _bidId The id of the bid/loan to get the borrower for.\n * @return borrower_ The address of the borrower associated with the bid.\n */\n function getLoanBorrower(\n uint256 _bidId\n ) public view returns (address borrower_) {\n borrower_ = bids[_bidId].borrower;\n }\n\n /**\n * @notice Returns the lender address for a given bid. If the stored lender address is the `LenderManager` NFT address, return the `ownerOf` for the bid ID.\n * @param _bidId The id of the bid/loan to get the lender for.\n * @return lender_ The address of the lender associated with the bid.\n */\n function getLoanLender(\n uint256 _bidId\n ) public view returns (address lender_) {\n lender_ = bids[_bidId].lender;\n\n if (lender_ == address(USING_LENDER_MANAGER)) {\n return lenderManager.ownerOf(_bidId);\n }\n\n //this is left in for backwards compatibility only\n if (lender_ == address(lenderManager)) {\n return lenderManager.ownerOf(_bidId);\n }\n }\n\n function getLoanLendingToken(\n uint256 _bidId\n ) external view returns (address token_) {\n token_ = address(bids[_bidId].loanDetails.lendingToken);\n }\n\n function getLoanMarketId(\n uint256 _bidId\n ) external view returns (uint256 _marketId) {\n _marketId = bids[_bidId].marketplaceId;\n }\n\n function getLoanSummary(\n uint256 _bidId\n )\n external\n view\n returns (\n address borrower,\n address lender,\n uint256 marketId,\n address principalTokenAddress,\n uint256 principalAmount,\n uint32 acceptedTimestamp,\n uint32 lastRepaidTimestamp,\n BidState bidState\n )\n {\n Bid storage bid = bids[_bidId];\n\n borrower = bid.borrower;\n lender = getLoanLender(_bidId);\n marketId = bid.marketplaceId;\n principalTokenAddress = address(bid.loanDetails.lendingToken);\n principalAmount = bid.loanDetails.principal;\n acceptedTimestamp = bid.loanDetails.acceptedTimestamp;\n lastRepaidTimestamp = V2Calculations.lastRepaidTimestamp(bids[_bidId]);\n bidState = bid.state;\n }\n\n /** OpenZeppelin Override Functions **/\n\n function _msgSender()\n internal\n view\n virtual\n override(ERC2771ContextUpgradeable, ContextUpgradeable)\n returns (address sender)\n {\n sender = ERC2771ContextUpgradeable._msgSender();\n }\n\n function _msgData()\n internal\n view\n virtual\n override(ERC2771ContextUpgradeable, ContextUpgradeable)\n returns (bytes calldata)\n {\n return ERC2771ContextUpgradeable._msgData();\n }\n}\n" + }, + "contracts/TellerV2Autopay.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"./interfaces/ITellerV2.sol\";\nimport \"./interfaces/ITellerV2Autopay.sol\";\n\nimport \"./libraries/NumbersLib.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport { Payment } from \"./TellerV2Storage.sol\";\n\n/**\n * @dev Helper contract to autopay loans\n */\ncontract TellerV2Autopay is OwnableUpgradeable, ITellerV2Autopay {\n using SafeERC20 for ERC20;\n using NumbersLib for uint256;\n\n ITellerV2 public immutable tellerV2;\n\n //bidId => enabled\n mapping(uint256 => bool) public loanAutoPayEnabled;\n\n // Autopay fee set for automatic loan payments\n uint16 private _autopayFee;\n\n /**\n * @notice This event is emitted when a loan is autopaid.\n * @param bidId The id of the bid/loan which was repaid.\n * @param msgsender The account that called the method\n */\n event AutoPaidLoanMinimum(uint256 indexed bidId, address indexed msgsender);\n\n /**\n * @notice This event is emitted when loan autopayments are enabled or disabled.\n * @param bidId The id of the bid/loan.\n * @param enabled Whether the autopayments are enabled or disabled\n */\n event AutoPayEnabled(uint256 indexed bidId, bool enabled);\n\n /**\n * @notice This event is emitted when the autopay fee has been updated.\n * @param newFee The new autopay fee set.\n * @param oldFee The previously set autopay fee.\n */\n event AutopayFeeSet(uint16 newFee, uint16 oldFee);\n\n constructor(address _protocolAddress) {\n tellerV2 = ITellerV2(_protocolAddress);\n }\n\n /**\n * @notice Initialized the proxy.\n * @param _fee The fee collected for automatic payment processing.\n * @param _owner The address of the ownership to be transferred to.\n */\n function initialize(uint16 _fee, address _owner) external initializer {\n _transferOwnership(_owner);\n _setAutopayFee(_fee);\n }\n\n /**\n * @notice Let the owner of the contract set a new autopay fee.\n * @param _newFee The new autopay fee to set.\n */\n function setAutopayFee(uint16 _newFee) public virtual onlyOwner {\n _setAutopayFee(_newFee);\n }\n\n function _setAutopayFee(uint16 _newFee) internal {\n // Skip if the fee is the same\n if (_newFee == _autopayFee) return;\n uint16 oldFee = _autopayFee;\n _autopayFee = _newFee;\n emit AutopayFeeSet(_newFee, oldFee);\n }\n\n /**\n * @notice Returns the current autopay fee.\n */\n function getAutopayFee() public view virtual returns (uint16) {\n return _autopayFee;\n }\n\n /**\n * @notice Function for a borrower to enable or disable autopayments\n * @param _bidId The id of the bid to cancel.\n * @param _autoPayEnabled boolean for allowing autopay on a loan\n */\n function setAutoPayEnabled(uint256 _bidId, bool _autoPayEnabled) external {\n require(\n _msgSender() == tellerV2.getLoanBorrower(_bidId),\n \"Only the borrower can set autopay\"\n );\n\n loanAutoPayEnabled[_bidId] = _autoPayEnabled;\n\n emit AutoPayEnabled(_bidId, _autoPayEnabled);\n }\n\n /**\n * @notice Function for a minimum autopayment to be performed on a loan\n * @param _bidId The id of the bid to repay.\n */\n function autoPayLoanMinimum(uint256 _bidId) external {\n require(\n loanAutoPayEnabled[_bidId],\n \"Autopay is not enabled for that loan\"\n );\n\n address lendingToken = ITellerV2(tellerV2).getLoanLendingToken(_bidId);\n address borrower = ITellerV2(tellerV2).getLoanBorrower(_bidId);\n\n uint256 amountToRepayMinimum = getEstimatedMinimumPayment(\n _bidId,\n block.timestamp\n );\n uint256 autopayFeeAmount = amountToRepayMinimum.percent(\n getAutopayFee()\n );\n\n // Pull lendingToken in from the borrower to this smart contract\n ERC20(lendingToken).safeTransferFrom(\n borrower,\n address(this),\n amountToRepayMinimum + autopayFeeAmount\n );\n\n // Transfer fee to msg sender\n ERC20(lendingToken).safeTransfer(_msgSender(), autopayFeeAmount);\n\n // Approve the lendingToken to tellerV2\n ERC20(lendingToken).approve(address(tellerV2), amountToRepayMinimum);\n\n // Use that lendingToken to repay the loan\n tellerV2.repayLoan(_bidId, amountToRepayMinimum);\n\n emit AutoPaidLoanMinimum(_bidId, msg.sender);\n }\n\n function getEstimatedMinimumPayment(uint256 _bidId, uint256 _timestamp)\n public\n virtual\n returns (uint256 _amount)\n {\n Payment memory estimatedPayment = tellerV2.calculateAmountDue(\n _bidId,\n _timestamp\n );\n\n _amount = estimatedPayment.principal + estimatedPayment.interest;\n }\n}\n" + }, + "contracts/TellerV2Context.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"./TellerV2Storage.sol\";\nimport \"./ERC2771ContextUpgradeable.sol\";\n\n/**\n * @dev This contract should not use any storage\n */\n\nabstract contract TellerV2Context is\n ERC2771ContextUpgradeable,\n TellerV2Storage\n{\n using EnumerableSet for EnumerableSet.AddressSet;\n\n event TrustedMarketForwarderSet(\n uint256 indexed marketId,\n address forwarder,\n address sender\n );\n event MarketForwarderApproved(\n uint256 indexed marketId,\n address indexed forwarder,\n address sender\n );\n event MarketForwarderRenounced(\n uint256 indexed marketId,\n address indexed forwarder,\n address sender\n );\n\n constructor(address trustedForwarder)\n ERC2771ContextUpgradeable(trustedForwarder)\n {}\n\n /**\n * @notice Checks if an address is a trusted forwarder contract for a given market.\n * @param _marketId An ID for a lending market.\n * @param _trustedMarketForwarder An address to check if is a trusted forwarder in the given market.\n * @return A boolean indicating the forwarder address is trusted in a market.\n */\n function isTrustedMarketForwarder(\n uint256 _marketId,\n address _trustedMarketForwarder\n ) public view returns (bool) {\n return\n _trustedMarketForwarders[_marketId] == _trustedMarketForwarder ||\n lenderCommitmentForwarder == _trustedMarketForwarder;\n }\n\n /**\n * @notice Checks if an account has approved a forwarder for a market.\n * @param _marketId An ID for a lending market.\n * @param _forwarder A forwarder contract address.\n * @param _account The address to verify set an approval.\n * @return A boolean indicating if an approval was set.\n */\n function hasApprovedMarketForwarder(\n uint256 _marketId,\n address _forwarder,\n address _account\n ) public view returns (bool) {\n return\n isTrustedMarketForwarder(_marketId, _forwarder) &&\n _approvedForwarderSenders[_forwarder].contains(_account);\n }\n\n /**\n * @notice Sets a trusted forwarder for a lending market.\n * @notice The caller must owner the market given. See {MarketRegistry}\n * @param _marketId An ID for a lending market.\n * @param _forwarder A forwarder contract address.\n */\n function setTrustedMarketForwarder(uint256 _marketId, address _forwarder)\n external\n {\n require(\n marketRegistry.getMarketOwner(_marketId) == _msgSender(),\n \"Caller must be the market owner\"\n );\n _trustedMarketForwarders[_marketId] = _forwarder;\n emit TrustedMarketForwarderSet(_marketId, _forwarder, _msgSender());\n }\n\n /**\n * @notice Approves a forwarder contract to use their address as a sender for a specific market.\n * @notice The forwarder given must be trusted by the market given.\n * @param _marketId An ID for a lending market.\n * @param _forwarder A forwarder contract address.\n */\n function approveMarketForwarder(uint256 _marketId, address _forwarder)\n external\n {\n require(\n isTrustedMarketForwarder(_marketId, _forwarder),\n \"Forwarder must be trusted by the market\"\n );\n _approvedForwarderSenders[_forwarder].add(_msgSender());\n emit MarketForwarderApproved(_marketId, _forwarder, _msgSender());\n }\n\n /**\n * @notice Renounces approval of a market forwarder\n * @param _marketId An ID for a lending market.\n * @param _forwarder A forwarder contract address.\n */\n function renounceMarketForwarder(uint256 _marketId, address _forwarder)\n external\n {\n if (_approvedForwarderSenders[_forwarder].contains(_msgSender())) {\n _approvedForwarderSenders[_forwarder].remove(_msgSender());\n emit MarketForwarderRenounced(_marketId, _forwarder, _msgSender());\n }\n }\n\n /**\n * @notice Retrieves the function caller address by checking the appended calldata if the _actual_ caller is a trusted forwarder.\n * @param _marketId An ID for a lending market.\n * @return sender The address to use as the function caller.\n */\n function _msgSenderForMarket(uint256 _marketId)\n internal\n view\n virtual\n returns (address)\n {\n if (\n msg.data.length >= 20 &&\n isTrustedMarketForwarder(_marketId, _msgSender())\n ) {\n address sender;\n assembly {\n sender := shr(96, calldataload(sub(calldatasize(), 20)))\n }\n // Ensure the appended sender address approved the forwarder\n require(\n _approvedForwarderSenders[_msgSender()].contains(sender),\n \"Sender must approve market forwarder\"\n );\n return sender;\n }\n\n return _msgSender();\n }\n\n /**\n * @notice Retrieves the actual function calldata from a trusted forwarder call.\n * @param _marketId An ID for a lending market to verify if the caller is a trusted forwarder.\n * @return calldata The modified bytes array of the function calldata without the appended sender's address.\n */\n function _msgDataForMarket(uint256 _marketId)\n internal\n view\n virtual\n returns (bytes calldata)\n {\n if (isTrustedMarketForwarder(_marketId, _msgSender())) {\n return msg.data[:msg.data.length - 20];\n } else {\n return _msgData();\n }\n }\n}\n" + }, + "contracts/TellerV2MarketForwarder_G1.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"./interfaces/ITellerV2.sol\";\n\nimport \"./interfaces/IMarketRegistry.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\n\n/**\n * @dev Simple helper contract to forward an encoded function call to the TellerV2 contract. See {TellerV2Context}\n */\nabstract contract TellerV2MarketForwarder_G1 is\n Initializable,\n ContextUpgradeable\n{\n using AddressUpgradeable for address;\n\n address public immutable _tellerV2;\n address public immutable _marketRegistry;\n\n struct CreateLoanArgs {\n uint256 marketId;\n address lendingToken;\n uint256 principal;\n uint32 duration;\n uint16 interestRate;\n string metadataURI;\n address recipient;\n }\n\n constructor(address _protocolAddress, address _marketRegistryAddress) {\n _tellerV2 = _protocolAddress;\n _marketRegistry = _marketRegistryAddress;\n }\n\n function getTellerV2() public view returns (address) {\n return _tellerV2;\n }\n\n function getMarketRegistry() public view returns (address) {\n return _marketRegistry;\n }\n\n function getTellerV2MarketOwner(uint256 marketId) public returns (address) {\n return IMarketRegistry(getMarketRegistry()).getMarketOwner(marketId);\n }\n\n /**\n * @dev Performs function call to the TellerV2 contract by appending an address to the calldata.\n * @param _data The encoded function calldata on TellerV2.\n * @param _msgSender The address that should be treated as the underlying function caller.\n * @return The encoded response from the called function.\n *\n * Requirements:\n * - The {_msgSender} address must set an approval on TellerV2 for this forwarder contract __before__ making this call.\n */\n function _forwardCall(bytes memory _data, address _msgSender)\n internal\n returns (bytes memory)\n {\n return\n address(_tellerV2).functionCall(\n abi.encodePacked(_data, _msgSender)\n );\n }\n\n /**\n * @notice Creates a new loan using the TellerV2 lending protocol.\n * @param _createLoanArgs Details describing the loan agreement.]\n * @param _borrower The borrower address for the new loan.\n */\n function _submitBid(\n CreateLoanArgs memory _createLoanArgs,\n address _borrower\n ) internal virtual returns (uint256 bidId) {\n bytes memory responseData;\n\n responseData = _forwardCall(\n abi.encodeWithSignature(\n \"submitBid(address,uint256,uint256,uint32,uint16,string,address)\",\n _createLoanArgs.lendingToken,\n _createLoanArgs.marketId,\n _createLoanArgs.principal,\n _createLoanArgs.duration,\n _createLoanArgs.interestRate,\n _createLoanArgs.metadataURI,\n _createLoanArgs.recipient\n ),\n _borrower\n );\n\n return abi.decode(responseData, (uint256));\n }\n\n /**\n * @notice Creates a new loan using the TellerV2 lending protocol.\n * @param _createLoanArgs Details describing the loan agreement.]\n * @param _borrower The borrower address for the new loan.\n */\n function _submitBidWithCollateral(\n CreateLoanArgs memory _createLoanArgs,\n Collateral[] memory _collateralInfo,\n address _borrower\n ) internal virtual returns (uint256 bidId) {\n bytes memory responseData;\n\n responseData = _forwardCall(\n abi.encodeWithSignature(\n \"submitBid(address,uint256,uint256,uint32,uint16,string,address,(uint8,uint256,uint256,address)[])\",\n _createLoanArgs.lendingToken,\n _createLoanArgs.marketId,\n _createLoanArgs.principal,\n _createLoanArgs.duration,\n _createLoanArgs.interestRate,\n _createLoanArgs.metadataURI,\n _createLoanArgs.recipient,\n _collateralInfo\n ),\n _borrower\n );\n\n return abi.decode(responseData, (uint256));\n }\n\n /**\n * @notice Accepts a new loan using the TellerV2 lending protocol.\n * @param _bidId The id of the new loan.\n * @param _lender The address of the lender who will provide funds for the new loan.\n */\n function _acceptBid(uint256 _bidId, address _lender)\n internal\n virtual\n returns (bool)\n {\n // Approve the borrower's loan\n _forwardCall(\n abi.encodeWithSelector(ITellerV2.lenderAcceptBid.selector, _bidId),\n _lender\n );\n\n return true;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "contracts/TellerV2MarketForwarder_G2.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport \"./interfaces/ITellerV2.sol\";\n\nimport \"./interfaces/IMarketRegistry.sol\";\nimport \"./interfaces/ITellerV2MarketForwarder.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\n\n/**\n * @dev Simple helper contract to forward an encoded function call to the TellerV2 contract. See {TellerV2Context}\n */\nabstract contract TellerV2MarketForwarder_G2 is\n Initializable,\n ContextUpgradeable,\n ITellerV2MarketForwarder\n{\n using AddressUpgradeable for address;\n\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable _tellerV2;\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable _marketRegistry;\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address _protocolAddress, address _marketRegistryAddress) {\n _tellerV2 = _protocolAddress;\n _marketRegistry = _marketRegistryAddress;\n }\n\n function getTellerV2() public view returns (address) {\n return _tellerV2;\n }\n\n function getMarketRegistry() public view returns (address) {\n return _marketRegistry;\n }\n\n function getTellerV2MarketOwner(uint256 marketId) public returns (address) {\n return IMarketRegistry(getMarketRegistry()).getMarketOwner(marketId);\n }\n\n /**\n * @dev Performs function call to the TellerV2 contract by appending an address to the calldata.\n * @param _data The encoded function calldata on TellerV2.\n * @param _msgSender The address that should be treated as the underlying function caller.\n * @return The encoded response from the called function.\n *\n * Requirements:\n * - The {_msgSender} address must set an approval on TellerV2 for this forwarder contract __before__ making this call.\n */\n function _forwardCall(bytes memory _data, address _msgSender)\n internal\n returns (bytes memory)\n {\n return\n address(_tellerV2).functionCall(\n abi.encodePacked(_data, _msgSender)\n );\n }\n\n /**\n * @notice Creates a new loan using the TellerV2 lending protocol.\n * @param _createLoanArgs Details describing the loan agreement.]\n * @param _borrower The borrower address for the new loan.\n */\n /*function _submitBid(\n CreateLoanArgs memory _createLoanArgs,\n address _borrower\n ) internal virtual returns (uint256 bidId) {\n bytes memory responseData;\n\n responseData = _forwardCall(\n abi.encodeWithSignature(\n \"submitBid(address,uint256,uint256,uint32,uint16,string,address)\",\n _createLoanArgs.lendingToken,\n _createLoanArgs.marketId,\n _createLoanArgs.principal,\n _createLoanArgs.duration,\n _createLoanArgs.interestRate,\n _createLoanArgs.metadataURI,\n _createLoanArgs.recipient\n ),\n _borrower\n );\n\n return abi.decode(responseData, (uint256));\n }*/\n\n /**\n * @notice Creates a new loan using the TellerV2 lending protocol.\n * @param _createLoanArgs Details describing the loan agreement.]\n * @param _borrower The borrower address for the new loan.\n */\n function _submitBidWithCollateral(\n CreateLoanArgs memory _createLoanArgs,\n address _borrower\n ) internal virtual returns (uint256 bidId) {\n bytes memory responseData;\n\n responseData = _forwardCall(\n abi.encodeWithSignature(\n \"submitBid(address,uint256,uint256,uint32,uint16,string,address,(uint8,uint256,uint256,address)[])\",\n _createLoanArgs.lendingToken,\n _createLoanArgs.marketId,\n _createLoanArgs.principal,\n _createLoanArgs.duration,\n _createLoanArgs.interestRate,\n _createLoanArgs.metadataURI,\n _createLoanArgs.recipient,\n _createLoanArgs.collateral\n ),\n _borrower\n );\n\n return abi.decode(responseData, (uint256));\n }\n\n /**\n * @notice Accepts a new loan using the TellerV2 lending protocol.\n * @param _bidId The id of the new loan.\n * @param _lender The address of the lender who will provide funds for the new loan.\n */\n function _acceptBid(uint256 _bidId, address _lender)\n internal\n virtual\n returns (bool)\n {\n // Approve the borrower's loan\n _forwardCall(\n abi.encodeWithSelector(ITellerV2.lenderAcceptBid.selector, _bidId),\n _lender\n );\n\n return true;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "contracts/TellerV2Storage.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\nimport { IMarketRegistry_V2 } from \"./interfaces/IMarketRegistry_V2.sol\";\nimport \"./interfaces/IEscrowVault.sol\";\nimport \"./interfaces/IReputationManager.sol\";\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./interfaces/ICollateralManagerV1.sol\";\nimport \"./interfaces/ICollateralManagerV2.sol\";\nimport { PaymentType, PaymentCycleType } from \"./libraries/V2Calculations.sol\";\nimport \"./interfaces/ILenderManager.sol\";\n\nenum BidState {\n NONEXISTENT,\n PENDING,\n CANCELLED,\n ACCEPTED,\n PAID,\n LIQUIDATED,\n CLOSED\n}\n\n/**\n * @notice Represents a total amount for a payment.\n * @param principal Amount that counts towards the principal.\n * @param interest Amount that counts toward interest.\n */\nstruct Payment {\n uint256 principal;\n uint256 interest;\n}\n\n/**\n * @notice Details about a loan request.\n * @param borrower Account address who is requesting a loan.\n * @param receiver Account address who will receive the loan amount.\n * @param lender Account address who accepted and funded the loan request.\n * @param marketplaceId ID of the marketplace the bid was submitted to.\n * @param metadataURI ID of off chain metadata to find additional information of the loan request.\n * @param loanDetails Struct of the specific loan details.\n * @param terms Struct of the loan request terms.\n * @param state Represents the current state of the loan.\n */\nstruct Bid {\n address borrower;\n address receiver;\n address lender; // if this is the LenderManager address, we use that .owner() as source of truth\n uint256 marketplaceId;\n bytes32 _metadataURI; // DEPRECATED\n LoanDetails loanDetails;\n Terms terms;\n BidState state;\n PaymentType paymentType; // DEPRECATED\n}\n\n/**\n * @notice Details about the loan.\n * @param lendingToken The token address for the loan.\n * @param principal The amount of tokens initially lent out.\n * @param totalRepaid Payment struct that represents the total principal and interest amount repaid.\n * @param timestamp Timestamp, in seconds, of when the bid was submitted by the borrower.\n * @param acceptedTimestamp Timestamp, in seconds, of when the bid was accepted by the lender.\n * @param lastRepaidTimestamp Timestamp, in seconds, of when the last payment was made\n * @param loanDuration The duration of the loan.\n */\nstruct LoanDetails {\n IERC20 lendingToken;\n uint256 principal;\n Payment totalRepaid;\n uint32 timestamp;\n uint32 acceptedTimestamp;\n uint32 lastRepaidTimestamp;\n uint32 loanDuration;\n}\n\n/**\n * @notice Information on the terms of a loan request\n * @param paymentCycleAmount Value of tokens expected to be repaid every payment cycle.\n * @param paymentCycle Duration, in seconds, of how often a payment must be made.\n * @param APR Annual percentage rating to be applied on repayments. (10000 == 100%)\n */\nstruct Terms {\n uint256 paymentCycleAmount;\n uint32 paymentCycle; // DEPRECATED\n uint16 APR;\n}\n\nabstract contract TellerV2Storage_G0 {\n /** Storage Variables */\n\n // Current number of bids.\n uint256 public nextBidId;\n\n // Mapping of bidId to bid information.\n mapping(uint256 => Bid) public bids;\n\n // Mapping of borrowers to borrower requests.\n mapping(address => uint256[]) public borrowerBids; //DEPRECATED\n\n // Mapping of volume filled by lenders.\n mapping(address => uint256) public __lenderVolumeFilled; // DEPRECATED\n\n // Volume filled by all lenders.\n uint256 public __totalVolumeFilled; // DEPRECATED\n\n // List of allowed lending tokens\n EnumerableSet.AddressSet internal __lendingTokensSet; // DEPRECATED\n\n IMarketRegistry_V2 public marketRegistry;\n IReputationManager public reputationManager;\n\n // Mapping of borrowers to borrower requests.\n mapping(address => EnumerableSet.UintSet) internal _borrowerBidsActive; //DEPRECATED\n\n mapping(uint256 => uint32) public bidDefaultDuration; //DEPRECATED\n mapping(uint256 => uint32) public bidExpirationTime; //DEPRECATED\n\n // Mapping of volume filled by lenders.\n // Asset address => Lender address => Volume amount\n mapping(address => mapping(address => uint256)) public lenderVolumeFilled;\n\n // Volume filled by all lenders.\n // Asset address => Volume amount\n mapping(address => uint256) public totalVolumeFilled;\n\n uint256 public version;\n\n // Mapping of metadataURIs by bidIds.\n // Bid Id => metadataURI string\n mapping(uint256 => string) public uris; //DEPRECATED\n}\n\nabstract contract TellerV2Storage_G1 is TellerV2Storage_G0 {\n // market ID => trusted forwarder\n mapping(uint256 => address) internal _trustedMarketForwarders;\n // trusted forwarder => set of pre-approved senders\n mapping(address => EnumerableSet.AddressSet)\n internal _approvedForwarderSenders;\n}\n\nabstract contract TellerV2Storage_G2 is TellerV2Storage_G1 {\n address public lenderCommitmentForwarder; //deprecated\n}\n\nabstract contract TellerV2Storage_G3 is TellerV2Storage_G2 {\n ICollateralManagerV1 public collateralManagerV1;\n}\n\nabstract contract TellerV2Storage_G4 is TellerV2Storage_G3 {\n // Address of the lender manager contract\n ILenderManager public lenderManager;\n // BidId to payment cycle type (custom or monthly)\n mapping(uint256 => PaymentCycleType) public bidPaymentCycleType; //DEPRECATED\n}\n\nabstract contract TellerV2Storage_G5 is TellerV2Storage_G4 {\n // Address of the lender manager contract\n IEscrowVault public escrowVault;\n}\n\nabstract contract TellerV2Storage_G6 is TellerV2Storage_G5 {\n ICollateralManagerV2 public collateralManagerV2;\n mapping(uint256 => address) public collateralManagerForBid; //if this is zero, that means v1\n}\n\nabstract contract TellerV2Storage_G7 is TellerV2Storage_G6 {\n // If this is zero for a bid, the bid will use the values in the bid struct / bidDefaultDuration / bidExpirationTime\n //need internal fns to do this if/then\n mapping(uint256 => bytes32) public bidMarketTermsId;\n}\n\nabstract contract TellerV2Storage is TellerV2Storage_G7 {}\n" + }, + "contracts/Types.sol": { + "content": "pragma solidity >=0.8.0 <0.9.0;\n// SPDX-License-Identifier: MIT\n\n// A representation of an empty/uninitialized UUID.\nbytes32 constant EMPTY_UUID = 0;\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/packages/contracts/tests/CollateralManagerV2_Fork_Test.sol b/packages/contracts/tests/CollateralManagerV2_Fork_Test.txt similarity index 97% rename from packages/contracts/tests/CollateralManagerV2_Fork_Test.sol rename to packages/contracts/tests/CollateralManagerV2_Fork_Test.txt index fa363110f..211ffae55 100644 --- a/packages/contracts/tests/CollateralManagerV2_Fork_Test.sol +++ b/packages/contracts/tests/CollateralManagerV2_Fork_Test.txt @@ -21,18 +21,6 @@ import "./integration/IntegrationFork.sol"; import "../contracts/interfaces/IWETH.sol"; -/* - - -TODO - - add a test that verifies that you can use 2 NFT from the same project - as collateral for a single loan - - -get test coverage up to 80 - -*/ contract CollateralManagerV2_Fork_Test is Testable, IntegrationForkSetup { CollateralManagerV2_Override collateralManagerV2; //User private borrower; diff --git a/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Integration_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Integration_Test.sol index 356e34d6f..56491b4c6 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Integration_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Integration_Test.sol @@ -16,6 +16,10 @@ import { LenderCommitmentForwarder_G2 } from "../../contracts/LenderCommitmentFo import { LenderCommitmentForwarder_G3 } from "../../contracts/LenderCommitmentForwarder/LenderCommitmentForwarder_G3.sol"; import { MarketRegistryMock } from "../../contracts/mock/MarketRegistryMock.sol"; + +import { IMarketRegistry_V2 } from "../../contracts/interfaces/IMarketRegistry_V2.sol"; + + import { PaymentType, PaymentCycleType } from "../../contracts/libraries/V2Calculations.sol"; import { Collateral, CollateralType } from "../../contracts/interfaces/escrow/ICollateralEscrowV1.sol"; @@ -46,7 +50,7 @@ contract LenderCommitmentForwarder_Integration_Test is Testable { ILenderCommitmentForwarder lenderCommitmentForwarder; TellerV2 tellerV2; - IMarketRegistry marketRegistry; + IMarketRegistry_V2 marketRegistry; WethMock wethMock; TestERC721Token erc721Token; @@ -58,7 +62,7 @@ contract LenderCommitmentForwarder_Integration_Test is Testable { tellerV2 = IntegrationTestHelpers.deployIntegrationSuite(); - marketRegistry = IMarketRegistry(tellerV2.marketRegistry()); + marketRegistry = IMarketRegistry_V2(tellerV2.marketRegistry()); LenderCommitmentForwarder_G3 _lenderCommitmentForwarder = new LenderCommitmentForwarder_G3( address(tellerV2), @@ -80,19 +84,29 @@ contract LenderCommitmentForwarder_Integration_Test is Testable { uint16 _feePercent = 900; PaymentType _paymentType = PaymentType.EMI; PaymentCycleType _paymentCycleType = PaymentCycleType.Seconds; + + + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:_paymentCycleDuration, + paymentDefaultDuration:_paymentDefaultDuration, + bidExpirationTime:_bidExpirationTime, + marketplaceFeePercent:_feePercent, + paymentType:_paymentType, + paymentCycleType:_paymentCycleType, + feeRecipient: address(marketOwner) + + }); vm.prank(address(marketOwner)); - uint256 marketId = marketRegistry.createMarket( + (uint256 marketId, )= marketRegistry.createMarket( address(marketOwner), - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, + false, false, - _paymentType, - _paymentCycleType, - "uri" + + "uri", + marketTerms ); wethMock.deposit{ value: 100e18 }(); diff --git a/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Unit_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Unit_Test.sol index 0baec2f0c..aac47662b 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Unit_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder/LenderCommitmentForwarder_Unit_Test.sol @@ -1446,7 +1446,7 @@ contract LenderCommitmentForwarderTest_TellerV2Mock is TellerV2Context { constructor() TellerV2Context(address(0)) {} function __setMarketRegistry(address _marketRegistry) external { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); } function getSenderForMarket(uint256 _marketId) diff --git a/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Integration_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Integration_Test.sol index b11e326fe..220704e60 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Integration_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Integration_Test.sol @@ -13,8 +13,9 @@ import "../../../integration/IntegrationTestHelpers.sol"; import "../../../../contracts/LenderCommitmentForwarder/extensions/ExtensionsContextUpgradeable.sol"; import { WethMock } from "../../../../contracts/mock/WethMock.sol"; +import { IMarketRegistry_V2 } from "../../../../contracts/interfaces/IMarketRegistry_V2.sol"; -import { TellerV2SolMock } from "../../../../contracts/mock/TellerV2SolMock.sol"; +import { TellerV2 } from "../../../../contracts/TellerV2.sol"; import { LenderCommitmentForwarderMock } from "../../../../contracts/mock/LenderCommitmentForwarderMock.sol"; import { MarketRegistryMock } from "../../../../contracts/mock/MarketRegistryMock.sol"; @@ -44,7 +45,9 @@ contract FlashRolloverLoan_Integration_Test is Testable { TellerV2 tellerV2; WethMock wethMock; ILenderCommitmentForwarder lenderCommitmentForwarder; - IMarketRegistry marketRegistry; + IMarketRegistry_V2 marketRegistry; + + uint256 marketId; event RolloverLoanComplete( address borrower, @@ -62,7 +65,7 @@ contract FlashRolloverLoan_Integration_Test is Testable { console.logAddress(address(tellerV2)); - marketRegistry = IMarketRegistry(tellerV2.marketRegistry()); + marketRegistry = IMarketRegistry_V2(tellerV2.marketRegistry()); LenderCommitmentForwarder_G3 _lenderCommitmentForwarder = new LenderCommitmentForwarder_G3( address(tellerV2), @@ -92,18 +95,24 @@ contract FlashRolloverLoan_Integration_Test is Testable { PaymentType _paymentType = PaymentType.EMI; PaymentCycleType _paymentCycleType = PaymentCycleType.Seconds; + IMarketRegistry_V2.MarketplaceTerms + memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration: _paymentCycleDuration, + paymentDefaultDuration: _paymentDefaultDuration, + bidExpirationTime: _bidExpirationTime, + marketplaceFeePercent: _feePercent, + paymentType: _paymentType, + paymentCycleType: _paymentCycleType, + feeRecipient: address(marketOwner) + }); + vm.prank(address(marketOwner)); - uint256 marketId = marketRegistry.createMarket( + (marketId, ) = marketRegistry.createMarket( address(marketOwner), - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, false, false, - _paymentType, - _paymentCycleType, - "uri" + "uri", + marketTerms ); wethMock.deposit{ value: 100e18 }(); @@ -125,7 +134,7 @@ contract FlashRolloverLoan_Integration_Test is Testable { address lendingToken = address(wethMock); //initial loan - need to pay back 1 weth + 0.1 weth (interest) to the lender - uint256 marketId = 1; + uint256 principalAmount = 1e18; uint32 duration = 365 days; uint16 interestRate = 1000; @@ -133,7 +142,7 @@ contract FlashRolloverLoan_Integration_Test is Testable { //wethMock.transfer(address(flashRolloverLoan), 100); vm.prank(address(borrower)); - uint256 loanId = tellerV2.submitBid( + uint256 bidId = tellerV2.submitBid( lendingToken, marketId, principalAmount, @@ -142,16 +151,24 @@ contract FlashRolloverLoan_Integration_Test is Testable { "", address(borrower) ); + + + vm.prank(address(lender)); wethMock.approve(address(tellerV2), 5e18); + + vm.prank(address(lender)); ( uint256 amountToProtocol, uint256 amountToMarketplace, uint256 amountToBorrower - ) = tellerV2.lenderAcceptBid(loanId); + ) = tellerV2.lenderAcceptBid(bidId); + + + vm.warp(365 days + 1); @@ -184,17 +201,18 @@ contract FlashRolloverLoan_Integration_Test is Testable { //should get 0.45 weth from accepting this commitment during the rollover process - FlashRolloverLoan_G1.AcceptCommitmentArgs memory _acceptCommitmentArgs = FlashRolloverLoan_G1 - .AcceptCommitmentArgs({ - commitmentId: commitmentId, - principalAmount: commitmentPrincipalAmount, - collateralAmount: 0, - collateralTokenId: 0, - collateralTokenAddress: address(0), - interestRate: interestRate, - loanDuration: duration - // merkleProof: new bytes32[](0) - }); + FlashRolloverLoan_G1.AcceptCommitmentArgs + memory _acceptCommitmentArgs = FlashRolloverLoan_G1 + .AcceptCommitmentArgs({ + commitmentId: commitmentId, + principalAmount: commitmentPrincipalAmount, + collateralAmount: 0, + collateralTokenId: 0, + collateralTokenAddress: address(0), + interestRate: interestRate, + loanDuration: duration + // merkleProof: new bytes32[](0) + }); ///approve forwarders @@ -232,9 +250,11 @@ contract FlashRolloverLoan_Integration_Test is Testable { vm.expectEmit(true, false, false, false); emit RolloverLoanComplete(address(borrower), 0, 0, 0); + + vm.prank(address(borrower)); flashRolloverLoan.rolloverLoanWithFlash( - loanId, + bidId, flashLoanAmount, borrowerAmount, _acceptCommitmentArgs diff --git a/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Unit_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Unit_Test.sol index 04ef0f7b5..7eb4755bf 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Unit_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G2_Unit_Test.sol @@ -477,7 +477,7 @@ contract FlashRolloverLoan_Unit_Test is Testable { ); } - function test_calculate_rollover_amount() public { + function test_calculate_rollover_amount_g2() public { address lendingToken = address(wethMock); //initial loan - need to pay back 1 weth + 0.1 weth (interest) to the lender @@ -558,7 +558,7 @@ contract FlashRolloverLoan_Unit_Test is Testable { assertEq(flashAmount, 55000, "invalid flashAmount"); assertEq(borrowerAmount, -10549, "invalid borrowerAmount"); - + /* (flashAmount, borrowerAmount) = flashRolloverLoan .calculateRolloverAmount( loanId, @@ -569,6 +569,8 @@ contract FlashRolloverLoan_Unit_Test is Testable { assertEq(flashAmount, 55000, "invalid flashAmount"); assertEq(borrowerAmount, -10500, "invalid borrowerAmount"); + + */ } } diff --git a/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G3_Integration_Test.sol b/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G3_Integration_Test.sol index 03524f823..f6a60a82d 100644 --- a/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G3_Integration_Test.sol +++ b/packages/contracts/tests/LenderCommitmentForwarder/extensions/FlashRolloverLoan/FlashRolloverLoan_G3_Integration_Test.sol @@ -13,6 +13,7 @@ import "../../../integration/IntegrationTestHelpers.sol"; import "../../../../contracts/LenderCommitmentForwarder/extensions/ExtensionsContextUpgradeable.sol"; import { WethMock } from "../../../../contracts/mock/WethMock.sol"; +import { IMarketRegistry_V2 } from "../../../../contracts/interfaces/IMarketRegistry_V2.sol"; import { TestERC721Token } from "../../../tokens/TestERC721Token.sol"; import { TellerV2SolMock } from "../../../../contracts/mock/TellerV2SolMock.sol"; @@ -44,9 +45,11 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { TellerV2 tellerV2; WethMock wethMock; ILenderCommitmentForwarder lenderCommitmentForwarder; - IMarketRegistry marketRegistry; + IMarketRegistry_V2 marketRegistry; TestERC721Token testNft; + uint256 marketId; + event RolloverLoanComplete( address borrower, uint256 originalLoanId, @@ -63,11 +66,9 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { console.logAddress(address(tellerV2)); - marketRegistry = IMarketRegistry(tellerV2.marketRegistry()); - - + marketRegistry = IMarketRegistry_V2(tellerV2.marketRegistry()); - LenderCommitmentForwarder_G3 _lenderCommitmentForwarder = new LenderCommitmentForwarder_G3( + LenderCommitmentForwarder_G3 _lenderCommitmentForwarder = new LenderCommitmentForwarder_G3( address(tellerV2), address(marketRegistry) ); @@ -99,18 +100,24 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { PaymentType _paymentType = PaymentType.EMI; PaymentCycleType _paymentCycleType = PaymentCycleType.Seconds; + IMarketRegistry_V2.MarketplaceTerms + memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration: _paymentCycleDuration, + paymentDefaultDuration: _paymentDefaultDuration, + bidExpirationTime: _bidExpirationTime, + marketplaceFeePercent: _feePercent, + paymentType: _paymentType, + paymentCycleType: _paymentCycleType, + feeRecipient: address(marketOwner) + }); + vm.prank(address(marketOwner)); - uint256 marketId = marketRegistry.createMarket( + (marketId, ) = marketRegistry.createMarket( address(marketOwner), - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, false, false, - _paymentType, - _paymentCycleType, - "uri" + "uri", + marketTerms ); wethMock.deposit{ value: 100e18 }(); @@ -140,21 +147,22 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { //wethMock.transfer(address(flashRolloverLoan), 100); vm.prank(address(borrower)); - uint256 loanId = tellerV2.submitBid( + uint256 bidId = tellerV2.submitBid( lendingToken, - 1, //market id + marketId, //market id principalAmount, duration, interestRate, "", address(borrower) ); + vm.prank(address(lender)); wethMock.approve(address(tellerV2), 5e18); vm.prank(address(lender)); - tellerV2.lenderAcceptBid(loanId); + tellerV2.lenderAcceptBid(bidId); vm.warp(365 days + 1); @@ -220,7 +228,7 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { { vm.prank(address(marketOwner)); ITellerV2Context(address(tellerV2)).setTrustedMarketForwarder( - 1, + marketId, address(lenderCommitmentForwarder) ); @@ -228,21 +236,21 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { vm.prank(address(lender)); ITellerV2Context(address(tellerV2)).approveMarketForwarder( - 1, + marketId, address(lenderCommitmentForwarder) ); vm.prank(address(borrower)); ITellerV2Context(address(tellerV2)).approveMarketForwarder( - 1, + marketId, address(lenderCommitmentForwarder) ); //borrower must approve the extension vm.prank(address(borrower)); IExtensionsContext(address(lenderCommitmentForwarder)).addExtension( - address(flashRolloverLoan) - ); + address(flashRolloverLoan) + ); address collateralManager = address(tellerV2.collateralManager()); @@ -259,7 +267,7 @@ contract FlashRolloverLoan_G3_Integration_Test is Testable { vm.prank(address(borrower)); flashRolloverLoan.rolloverLoanWithFlash( - loanId, + bidId, flashLoanAmount, 0, _acceptCommitmentArgs diff --git a/packages/contracts/tests/MarketForwarder_Combined_Test.sol b/packages/contracts/tests/MarketForwarder_Combined_Test.sol index 0aed78f3a..92264763e 100644 --- a/packages/contracts/tests/MarketForwarder_Combined_Test.sol +++ b/packages/contracts/tests/MarketForwarder_Combined_Test.sol @@ -141,7 +141,7 @@ contract MarketForwarderTester is TellerV2Context { constructor() TellerV2Context(address(0)) {} function __setMarketRegistry(address _marketRegistry) external { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); } function getSenderForMarket(uint256 _marketId) diff --git a/packages/contracts/tests/MarketForwarder_Test.sol b/packages/contracts/tests/MarketForwarder_Test.sol index 53bd9e336..58749e0e6 100644 --- a/packages/contracts/tests/MarketForwarder_Test.sol +++ b/packages/contracts/tests/MarketForwarder_Test.sol @@ -150,7 +150,7 @@ contract MarketForwarderTellerV2Mock is TellerV2Context { constructor() TellerV2Context(address(0)) {} function setMarketRegistry(address _marketRegistry) external { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); } function getSenderForMarket(uint256 _marketId) diff --git a/packages/contracts/tests/MarketRegistry_Override.sol b/packages/contracts/tests/MarketRegistry_Override.sol index 27360ffc1..8fd18c031 100644 --- a/packages/contracts/tests/MarketRegistry_Override.sol +++ b/packages/contracts/tests/MarketRegistry_Override.sol @@ -46,7 +46,7 @@ contract MarketRegistry_Override is MarketRegistry { globalMarketOwner = _owner; } - function attestStakeholder( + /* function attestStakeholder( uint256 _marketId, address _stakeholderAddress, uint256 _expirationTime, @@ -60,13 +60,14 @@ contract MarketRegistry_Override is MarketRegistry { ); } + function revokeStakeholder( uint256 _marketId, address _stakeholderAddress, bool _isLender ) public { super._revokeStakeholder(_marketId, _stakeholderAddress, _isLender); - } + }*/ function attestStakeholderVerification( uint256 _marketId, @@ -77,7 +78,7 @@ contract MarketRegistry_Override is MarketRegistry { super._attestStakeholderVerification( _marketId, _stakeholderAddress, - _uuid, + // _uuid, _isLender ); } @@ -118,7 +119,7 @@ contract MarketRegistry_Override is MarketRegistry { return markets[_marketId].verifiedBorrowersForMarket.contains(guy); } - function getLenderAttestationId(uint256 _marketId, address guy) + /* function getLenderAttestationId(uint256 _marketId, address guy) public returns (bytes32) { @@ -130,7 +131,7 @@ contract MarketRegistry_Override is MarketRegistry { returns (bytes32) { return markets[_marketId].borrowerAttestationIds[guy]; - } + }*/ /* @notice returns the actual value in the markets storage mapping, not globalMarketOwner the override @@ -152,10 +153,10 @@ contract MarketRegistry_Override is MarketRegistry { public returns (bool isVerified_, bytes32 uuid_) { - (isVerified_, uuid_) = super._isVerified( + isVerified_ = super._isVerified( _stakeholderAddress, markets[_marketId].lenderAttestationRequired, - markets[_marketId].lenderAttestationIds, + // markets[_marketId].lenderAttestationIds, markets[_marketId].verifiedLendersForMarket ); } @@ -183,12 +184,12 @@ contract MarketRegistry_Override is MarketRegistry { function _attestStakeholderVerification( uint256 _marketId, address _stakeholderAddress, - bytes32 _uuid, + // bytes32 _uuid, bool _isLender ) internal override { attestStakeholderVerificationWasCalled = true; } - +/* function _attestStakeholderViaDelegation( uint256 _marketId, address _stakeholderAddress, @@ -199,7 +200,7 @@ contract MarketRegistry_Override is MarketRegistry { bytes32 _s ) internal override { attestStakeholderViaDelegationWasCalled = true; - } + }*/ function _revokeStakeholder( uint256 _marketId, @@ -208,22 +209,22 @@ contract MarketRegistry_Override is MarketRegistry { ) internal override { revokeStakeholderWasCalled = true; } - +/* function _revokeStakeholderVerification( uint256 _marketId, address _stakeholderAddress, bool _isLender ) internal override returns (bytes32 uuid_) { revokeStakeholderVerificationWasCalled = true; - } + }*/ function _isVerified( address _stakeholderAddress, bool _attestationRequired, - mapping(address => bytes32) storage _stakeholderAttestationIds, + // mapping(address => bytes32) storage _stakeholderAttestationIds, EnumerableSet.AddressSet storage _verifiedStakeholderForMarket - ) internal view override returns (bool isVerified_, bytes32 uuid_) { + ) internal view override returns (bool isVerified_ ) { isVerified_ = true; - uuid_ = bytes32("0x42"); + // uuid_ = bytes32("0x42"); } } diff --git a/packages/contracts/tests/MarketRegistry_Test.sol b/packages/contracts/tests/MarketRegistry_Test.sol index f7ca9208e..89cc8d4d9 100644 --- a/packages/contracts/tests/MarketRegistry_Test.sol +++ b/packages/contracts/tests/MarketRegistry_Test.sol @@ -11,13 +11,13 @@ import "../contracts/TellerV2Context.sol"; import "../contracts/TellerV2Storage.sol"; import "../contracts/interfaces/IMarketRegistry.sol"; +import "../contracts/interfaces/IMarketRegistry_V2.sol"; import "../contracts/EAS/TellerAS.sol"; import "../contracts/mock/WethMock.sol"; import "../contracts/interfaces/IWETH.sol"; - -import { User } from "./Test_Helpers.sol"; + import { PaymentType, PaymentCycleType } from "../contracts/libraries/V2Calculations.sol"; import { MarketRegistry_Override } from "./MarketRegistry_Override.sol"; @@ -25,11 +25,11 @@ import { MarketRegistry_Override } from "./MarketRegistry_Override.sol"; import { TellerASMock } from "../contracts/mock/TellerASMock.sol"; contract MarketRegistry_Test is Testable { - MarketRegistryUser private marketOwner; - MarketRegistryUser private borrower; - MarketRegistryUser private lender; - MarketRegistryUser private stakeholder; - MarketRegistryUser private feeRecipient; + User private marketOwner; + User private borrower; + User private lender; + //User private stakeholder; + User private feeRecipient; WethMock wethMock; @@ -55,24 +55,12 @@ contract MarketRegistry_Test is Testable { tellerASMock = new TellerASMock(); - marketRegistry.initialize(tellerASMock); + - marketOwner = new MarketRegistryUser( - address(tellerV2), - address(marketRegistry) - ); - borrower = new MarketRegistryUser( - address(tellerV2), - address(marketRegistry) - ); - lender = new MarketRegistryUser( - address(tellerV2), - address(marketRegistry) - ); - feeRecipient = new MarketRegistryUser( - address(tellerV2), - address(marketRegistry) - ); + marketOwner = new User( ); + borrower = new User( ); + lender = new User( ); + feeRecipient = new User( ); marketRegistry.setMarketOwner(address(marketOwner)); @@ -102,35 +90,59 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation function test_createMarket_simple() public { // Standard seconds payment cycle - uint256 marketId = marketOwner.createMarketSimple( - address(marketRegistry), - uint32(8000), - uint32(7000), - uint32(5000), - uint16(500), - false, + + + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(8000), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(marketRegistry) + }); + + vm.prank(address(marketOwner)); + (uint256 marketId, ) = marketRegistry.createMarket ( + address(marketOwner), false, - "uri://" + false, + "uri://", + marketTerms ); - (address owner, , , , , , ) = marketRegistry.getMarketData(marketId); + (address owner, , , , ) = marketRegistry.getMarketData(marketId); assertEq(owner, address(marketOwner), "Market not created"); } function test_closeMarket() public { - uint256 marketId = marketOwner.createMarketSimple( - address(marketRegistry), - uint32(8000), - uint32(7000), - uint32(5000), - uint16(500), - false, + + + + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(8000), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(marketRegistry) + }); + + vm.prank(address(marketOwner)); + (uint256 marketId, ) = marketRegistry.createMarket ( + address(marketRegistry), false, - "uri://" + false, + "uri://", + marketTerms ); - marketOwner.closeMarket(marketId); + vm.prank(address(marketOwner)); + marketRegistry.closeMarket(marketId); bool marketIsClosed = marketRegistry.isMarketClosed(marketId); @@ -138,20 +150,33 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation } function test_closeMarket_twice() public { - uint256 marketId = marketOwner.createMarketSimple( - address(marketRegistry), - uint32(8000), - uint32(7000), - uint32(5000), - uint16(500), - false, + + + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(8000), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(marketRegistry) + }); + + vm.prank(address(marketOwner)); + (uint256 marketId, ) = marketRegistry.createMarket ( + address(marketRegistry), false, - "uri://" + false, + "uri://", + marketTerms ); - marketOwner.closeMarket(marketId); + vm.prank(address(marketOwner)); + marketRegistry.closeMarket(marketId); - marketOwner.closeMarket(marketId); + vm.prank(address(marketOwner)); + marketRegistry.closeMarket(marketId); bool marketIsClosed = marketRegistry.isMarketClosed(marketId); @@ -159,42 +184,64 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation } function test_closeMarket_invalid_owner() public { - uint256 marketId = marketOwner.createMarketSimple( - address(marketRegistry), - uint32(8000), - uint32(7000), - uint32(5000), - uint16(500), - false, + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(8000), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(marketRegistry) + }); + + vm.prank(address(marketOwner)); + (uint256 marketId, ) = marketRegistry.createMarket ( + address(marketRegistry), false, - "uri://" + false, + "uri://", + marketTerms ); vm.expectRevert("Not the owner"); - borrower.closeMarket(marketId); + marketRegistry.closeMarket(marketId); } function test_createMarket() public { // Standard seconds payment cycle - marketOwner.createMarket( - address(marketRegistry), - 8000, - 7000, - 5000, - 500, - false, + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(8000), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(marketRegistry) + }); + + vm.prank(address(marketOwner)); + (uint256 marketId, ) = marketRegistry.createMarket ( + address(marketRegistry), false, - PaymentType.EMI, - PaymentCycleType.Seconds, - "uri://" + false, + "uri://", + marketTerms ); + + uint256 _marketId = 1; + + bytes32 marketTermsId = marketRegistry.getCurrentTermsForMarket(_marketId); + ( uint32 paymentCycleDuration, - PaymentCycleType paymentCycle - ) = marketRegistry.getPaymentCycle(1); + PaymentCycleType paymentCycleType, + , + , + ) = marketRegistry.getMarketTermsForLending(marketTermsId); require( - paymentCycle == PaymentCycleType.Seconds, + paymentCycleType == PaymentCycleType.Seconds, "Market payment cycle type incorrectly created" ); @@ -204,39 +251,74 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation "Market payment cycle duration set incorrectly" ); - // Monthly payment cycle - marketOwner.createMarket( - address(marketRegistry), - 0, - 7000, - 5000, - 500, - false, + + marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(0), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Monthly, + feeRecipient: address(marketRegistry) + }); + + vm.prank(address(marketOwner)); + (marketId, ) = marketRegistry.createMarket ( + address(marketRegistry), false, - PaymentType.EMI, - PaymentCycleType.Monthly, - "uri://" + false, + "uri://", + marketTerms ); - (paymentCycleDuration, paymentCycle) = marketRegistry.getPaymentCycle( - 2 + + _marketId = 2; + + marketTermsId = marketRegistry.getCurrentTermsForMarket(_marketId); + + (paymentCycleDuration, paymentCycleType, , ,) = marketRegistry.getMarketTermsForLending( + marketTermsId ); require( - paymentCycle == PaymentCycleType.Monthly, + paymentCycleType == PaymentCycleType.Monthly, "Monthly market payment cycle type incorrectly created" ); assertEq( paymentCycleDuration, 30 days, - "Monthly market payment cycle duration set incorrectly" + "Monthly market payment cycle duration returned incorrectly" ); - vm.expectRevert("monthly payment cycle duration cannot be set"); + + + // Monthly payment cycle should fail - marketOwner.createMarket( + marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(3000), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Monthly, + feeRecipient: address(marketRegistry) + }); + + //payment cycle duration must be zero for monthly type + vm.expectRevert("Monthly payment cycle duration invalid for cycle type"); + vm.prank(address(marketOwner)); + (marketId, ) = marketRegistry.createMarket ( + address(marketRegistry), + false, + false, + "uri://", + marketTerms + ); + + + /* marketOwner.createMarket( address(marketRegistry), 3000, 7000, @@ -246,30 +328,42 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation false, PaymentType.EMI, PaymentCycleType.Monthly, + address(marketRegistry), "uri://" - ); + ); */ } function test_createMarket_invalid_initial_owner() public { + + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:uint32(0), + paymentDefaultDuration:uint32(7000), + bidExpirationTime:uint32(5000), + marketplaceFeePercent:uint16(500), + paymentType: PaymentType.EMI, + paymentCycleType:PaymentCycleType.Monthly, + feeRecipient: address(marketRegistry) + }); + + + vm.expectRevert(); //"Invalid owner address" - marketOwner.createMarket( - address(0), - 0, - 7000, - 5000, - 500, - false, + (uint256 marketId, ) = marketRegistry.createMarket ( + address(0), false, - PaymentType.EMI, - PaymentCycleType.Seconds, - "uri://" + false, + "uri://", + marketTerms ); + } +/* function test_attestStakeholder() public { bool isLender = true; - - marketOwner.attestStakeholder( + vm.prank(address(marketOwner)); + marketRegistry.attestStakeholderInternal( marketId, address(lender), expirationTime, @@ -294,7 +388,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation expirationTime, isLender ); - } + }*/ function test_attestStakeholderVerification_lender() public { bool isLender = true; @@ -316,12 +410,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation true, "Did not add lender to verified set" ); - - assertEq( - marketRegistry.getLenderAttestationId(marketId, address(lender)), - uuid, - "Did not set market attestation Id" - ); + } function test_attestStakeholderVerification_borrower() public { @@ -345,14 +434,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation "Did not add lender to verified set" ); - assertEq( - marketRegistry.getBorrowerAttestationId( - marketId, - address(borrower) - ), - uuid, - "Did not set market attestation Id" - ); + } function test_attestLender() public { @@ -367,22 +449,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation function test_attestLender_expired() public {} - function test_attestLenderDelegated() public { - marketRegistry.attestLender( - marketId, - address(lender), - expirationTime, - v, - r, - s - ); - - assertEq( - marketRegistry.attestStakeholderViaDelegationWasCalled(), - true, - "Attest stakeholder via delegation was not called" - ); - } + function test_attestBorrower() public { marketRegistry.attestBorrower( @@ -397,24 +464,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation "Attest stakeholder was not called" ); } - - function test_attestBorrowerDelegated() public { - marketRegistry.attestBorrower( - marketId, - address(lender), - expirationTime, - v, - r, - s - ); - - assertEq( - marketRegistry.attestStakeholderViaDelegationWasCalled(), - true, - "Attest stakeholder via delegation was not called" - ); - } - + function test_revokeLender() public { marketRegistry.revokeLender(marketId, address(lender)); @@ -435,10 +485,11 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation ); } - function test_revokeStakeholder() public { + /* function test_revokeStakeholder() public { bool isLender = true; - marketOwner.revokeStakeholder(marketId, address(lender), isLender); + vm.prank(address(marketOwner)); + marketRegistry.revokeStakeholder(marketId, address(lender), isLender); assertEq( marketRegistry.revokeStakeholderVerificationWasCalled(), @@ -455,25 +506,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation marketRegistry.revokeStakeholder(marketId, address(lender), isLender); } - function test_revokeLenderViaDelegation() public { - marketRegistry.revokeLender(marketId, address(lender), v, r, s); - - assertEq( - marketRegistry.revokeStakeholderVerificationWasCalled(), - true, - "Revoke stakeholder verification was not called" - ); - } - - function test_revokeBorrowerViaDelegation() public { - marketRegistry.revokeBorrower(marketId, address(borrower), v, r, s); - - assertEq( - marketRegistry.revokeStakeholderVerificationWasCalled(), - true, - "Revoke stakeholder verification was not called" - ); - } + */ function test_revokeStakeholderVerification() public { bool isLender = true; @@ -499,7 +532,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation function test_lenderExitMarket() public { marketRegistry.forceVerifyLenderForMarket(marketId, address(lender)); - lender.lenderExitMarket(marketId); + vm.prank(address(lender)); + marketRegistry.lenderExitMarket(marketId); assertEq( marketRegistry.marketVerifiedLendersContains( @@ -516,8 +550,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation marketId, address(borrower) ); - - borrower.borrowerExitMarket(marketId); + vm.prank(address(borrower)); + marketRegistry.borrowerExitMarket(marketId); assertEq( marketRegistry.marketVerifiedBorrowersContains( @@ -556,39 +590,50 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation marketRegistry.stubMarket(marketId, address(this)); + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:111, + paymentDefaultDuration:200, + bidExpirationTime:300, + marketplaceFeePercent:10, + paymentType:PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(address(this)) + + }); + + marketRegistry.updateMarketSettings( marketId, - 111, - PaymentType.EMI, - PaymentCycleType.Seconds, - 200, - 300, - 10, - false, - false, - "ipfs://" + marketTerms + ); - (address owner, uint32 paymentCycleDuration, , , , , ) = marketRegistry - .getMarketData(marketId); + bytes32 marketTermsId = marketRegistry.getCurrentTermsForMarket(marketId); + + ( uint32 paymentCycleDuration, , , , , , ) = marketRegistry + .getMarketTermsData(marketTermsId); assertEq(paymentCycleDuration, 111, "Market not updated"); } function test_updateMarketSettings_not_owner() public { - vm.expectRevert("Not the owner"); + + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:111, + paymentDefaultDuration:200, + bidExpirationTime:300, + marketplaceFeePercent:10, + paymentType:PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(address(this)) + }); + + vm.expectRevert("Not the owner"); marketRegistry.updateMarketSettings( marketId, - 111, - PaymentType.EMI, - PaymentCycleType.Seconds, - 200, - 300, - 10, - false, - false, - "ipfs://" + marketTerms ); } @@ -621,7 +666,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation ); } - function test_setMarketFeeRecipient() public { + /* function test_setMarketFeeRecipient() public { marketRegistry.setMarketOwner(address(this)); marketRegistry.stubMarket(marketId, address(this)); @@ -643,7 +688,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation vm.expectRevert("Not the owner"); vm.prank(address(borrower)); marketRegistry.setMarketFeeRecipient(marketId, address(lender)); - } + }*/ function test_setMarketURI() public { marketRegistry.setMarketOwner(address(this)); @@ -669,8 +714,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation marketRegistry.setMarketURI(marketId, "ipfs://"); } - //test more branches of this - function test_setPaymentCycle() public { + + /* function test_setPaymentCycle() public { marketRegistry.setMarketOwner(address(this)); marketRegistry.stubMarket(marketId, address(this)); @@ -724,8 +769,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation vm.expectRevert("monthly payment cycle duration cannot be set"); marketRegistry.setPaymentCycle(marketId, PaymentCycleType.Monthly, 555); - } - + }*/ +/* function test_setPaymentDefaultDuration() public { marketRegistry.setMarketOwner(address(this)); @@ -749,7 +794,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation vm.prank(address(borrower)); marketRegistry.setPaymentDefaultDuration(marketId, 555); } - +*/ +/* function test_setBidExpirationTime() public { marketRegistry.setMarketOwner(address(this)); @@ -773,7 +819,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation vm.prank(address(borrower)); marketRegistry.setBidExpirationTime(marketId, 555); } - +*/ +/* function test_setMarketFeePercent() public { marketRegistry.setMarketOwner(address(this)); @@ -797,7 +844,8 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation vm.prank(address(borrower)); marketRegistry.setMarketFeePercent(marketId, 555); } - +*/ +/* function test_setMarketPaymentType() public { marketRegistry.setMarketOwner(address(this)); @@ -833,7 +881,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation "Could not set market payment type" ); } - +*/ function test_setLenderAttestationRequired() public { marketRegistry.setMarketOwner(address(this)); @@ -1042,7 +1090,7 @@ FNDA:0,MarketRegistry._attestStakeholderViaDelegation assertEq(lenders[0], address(lender), "Did not return correct lender"); } } - +/* contract MarketRegistryUser is User { MarketRegistry_Override marketRegistry; @@ -1088,6 +1136,9 @@ contract MarketRegistryUser is User { ); } } +*/ + +contract User{} contract TellerV2Mock is TellerV2Context { Bid mockBid; @@ -1095,7 +1146,7 @@ contract TellerV2Mock is TellerV2Context { constructor() TellerV2Context(address(0)) {} function setMarketRegistry(address _marketRegistry) external { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); } function getSenderForMarket(uint256 _marketId) diff --git a/packages/contracts/tests/TellerV2/TellerV2_Override.sol b/packages/contracts/tests/TellerV2/TellerV2_Override.sol index b09227885..bc183e91e 100644 --- a/packages/contracts/tests/TellerV2/TellerV2_Override.sol +++ b/packages/contracts/tests/TellerV2/TellerV2_Override.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { TellerV2, Bid, BidState, Collateral, Payment, LoanDetails, Terms } from "../../contracts/TellerV2.sol"; +import { TellerV2, Bid, BidState, Collateral, Payment, LoanDetails, Terms, PaymentCycleType } from "../../contracts/TellerV2.sol"; import "../../contracts/interfaces/IMarketRegistry.sol"; +import "../../contracts/interfaces/IMarketRegistry_V2.sol"; + import "../../contracts/interfaces/IReputationManager.sol"; import "../../contracts/interfaces/ICollateralManager.sol"; import "../../contracts/interfaces/ICollateralManagerV1.sol"; @@ -49,7 +51,7 @@ contract TellerV2_Override is TellerV2 { } function setMarketRegistrySuper(address _marketRegistry) public { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); } function setCollateralManagerSuper(address _collateralManager) public { diff --git a/packages/contracts/tests/TellerV2/TellerV2_Test.sol b/packages/contracts/tests/TellerV2/TellerV2_Test.sol index 0fbe6fd23..c960c3440 100644 --- a/packages/contracts/tests/TellerV2/TellerV2_Test.sol +++ b/packages/contracts/tests/TellerV2/TellerV2_Test.sol @@ -8,6 +8,7 @@ import { MarketRegistry } from "../../contracts/MarketRegistry.sol"; import { ReputationManager } from "../../contracts/ReputationManager.sol"; import "../../contracts/interfaces/IMarketRegistry.sol"; +import "../../contracts/interfaces/IMarketRegistry_V2.sol"; import "../../contracts/interfaces/IReputationManager.sol"; import "../../contracts/EAS/TellerAS.sol"; @@ -25,7 +26,7 @@ import "../tokens/TestERC20Token.sol"; //import "../../contracts/CollateralManagerV1.sol"; import "../../contracts/mock/CollateralManagerMock.sol"; import { Collateral } from "../../contracts/interfaces/escrow/ICollateralEscrowV1.sol"; -import { PaymentType } from "../../contracts/libraries/V2Calculations.sol"; +import { PaymentType, PaymentCycleType } from "../../contracts/libraries/V2Calculations.sol"; import { BidState, Payment } from "../../contracts/TellerV2Storage.sol"; import "../../contracts/MetaForwarder.sol"; @@ -61,7 +62,7 @@ contract TellerV2_Test is Testable { tellerV2 = new TellerV2(address(0)); // Deploy MarketRegistry & ReputationManager - IMarketRegistry marketRegistry = IMarketRegistry(new MarketRegistry()); + IMarketRegistry_V2 marketRegistry = IMarketRegistry_V2(new MarketRegistry()); IReputationManager reputationManager = IReputationManager( new ReputationManager() ); @@ -114,18 +115,29 @@ contract TellerV2_Test is Testable { // Approve Teller V2 for the lender's dai lender.addAllowance(address(daiMock), address(tellerV2), balance * 10); - // Create a market - marketId1 = marketOwner.createMarket( + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:8000, + paymentDefaultDuration:7000, + bidExpirationTime:5000, + marketplaceFeePercent:500, + paymentType:PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(this) + + }); + + vm.prank(address(marketOwner)); + + // Create a market + (marketId1,) = marketRegistry.createMarket( address(marketRegistry), - 8000, - 7000, - 5000, - 500, + false, false, - PaymentType.EMI, - PaymentCycleType.Seconds, - "uri://" + + "uri://", + marketTerms ); } diff --git a/packages/contracts/tests/TellerV2/TellerV2_bids.sol b/packages/contracts/tests/TellerV2/TellerV2_bids.sol index 0f5978be3..841107d96 100644 --- a/packages/contracts/tests/TellerV2/TellerV2_bids.sol +++ b/packages/contracts/tests/TellerV2/TellerV2_bids.sol @@ -130,8 +130,11 @@ contract TellerV2_bids_test is Testable { function test_submit_bid_internal() public { tellerV2.setMarketRegistrySuper(address(marketRegistryMock)); + marketRegistryMock.mock_setGlobalMarketsClosed(false); + marketRegistryMock.forceSetGlobalTermsForMarket(bytes32("0x01")); - vm.expectEmit(false, false, false, false); + + /* vm.expectEmit(false, false, false, false); emit SubmittedBid( 0, @@ -139,6 +142,26 @@ contract TellerV2_bids_test is Testable { address(this), keccak256(abi.encodePacked("")) ); + */ + + uint256 bidId = tellerV2._submitBidSuper( + address(lendingToken), // lending token + 1, // market ID + 100, // principal + 365 days, // duration + 20_00, // interest rate + "", // metadata URI + address(this) // receiver + ); + } + + function test_submit_bid_internal_fails_without_terms() public { + tellerV2.setMarketRegistrySuper(address(marketRegistryMock)); + marketRegistryMock.mock_setGlobalMarketsClosed(false); + marketRegistryMock.forceSetGlobalTermsForMarket(bytes32(0)); + + + vm.expectRevert("Market does not have assigned terms."); uint256 bidId = tellerV2._submitBidSuper( address(lendingToken), // lending token @@ -150,9 +173,11 @@ contract TellerV2_bids_test is Testable { address(this) // receiver ); } + function test_submit_bid_internal_fails_when_market_closed() public { tellerV2.setMarketRegistrySuper(address(marketRegistryMock)); + marketRegistryMock.forceSetGlobalTermsForMarket(bytes32("0x01")); marketRegistryMock.mock_setGlobalMarketsClosed(true); diff --git a/packages/contracts/tests/TellerV2Autopay_Test.sol b/packages/contracts/tests/TellerV2Autopay_Test.sol index a6ca178aa..4360d0c62 100644 --- a/packages/contracts/tests/TellerV2Autopay_Test.sol +++ b/packages/contracts/tests/TellerV2Autopay_Test.sol @@ -12,6 +12,9 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../contracts/TellerV2Storage.sol"; import "../contracts/interfaces/IMarketRegistry.sol"; + +import "../contracts/interfaces/IMarketRegistry_V2.sol"; + import "../contracts/interfaces/IReputationManager.sol"; import "../contracts/EAS/TellerAS.sol"; @@ -65,8 +68,8 @@ contract TellerV2Autopay_Test is Testable, TellerV2Autopay { } function setAutoPayEnabled_before() public { - uint256 marketplaceId = 1; - marketOwner.createMarketWithinRegistry( + + /*marketOwner.createMarketWithinRegistry( address(marketRegistry), 8000, 7000, @@ -76,8 +79,32 @@ contract TellerV2Autopay_Test is Testable, TellerV2Autopay { false, PaymentType.EMI, "uri://" + );*/ + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:8000, + paymentDefaultDuration:7000, + bidExpirationTime:5000, + marketplaceFeePercent:500, + paymentType:PaymentType.EMI, + paymentCycleType:PaymentCycleType.Seconds, + feeRecipient: address(this) + + }); + + (uint256 marketplaceId, ) = IMarketRegistry_V2(marketRegistry).createMarket( + address(this), + + false, + false, + + "uri://", + marketTerms ); + + + uint256 bidId = borrower.submitBid( address(wethMock), marketplaceId, @@ -225,7 +252,7 @@ contract User { ITellerV2Autopay(tellerV2Autopay).setAutoPayEnabled(bidId, enabled); } - function createMarketWithinRegistry( + /*function createMarketWithinRegistry( address marketRegistry, uint32 _paymentCycleDuration, uint32 _paymentDefaultDuration, @@ -236,19 +263,9 @@ contract User { PaymentType _paymentType, string calldata _uri ) public { - IMarketRegistry(marketRegistry).createMarket( - address(this), - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, - _requireLenderAttestation, - _requireBorrowerAttestation, - _paymentType, - PaymentCycleType.Seconds, - _uri - ); - } + + + }*/ function autoPayLoanMinimum(uint256 bidId) public { ITellerV2Autopay(tellerV2Autopay).autoPayLoanMinimum(bidId); diff --git a/packages/contracts/tests/TellerV2Context/TellerV2Context_Override.sol b/packages/contracts/tests/TellerV2Context/TellerV2Context_Override.sol index bc3084255..35c8252bd 100644 --- a/packages/contracts/tests/TellerV2Context/TellerV2Context_Override.sol +++ b/packages/contracts/tests/TellerV2Context/TellerV2Context_Override.sol @@ -5,6 +5,7 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { TellerV2Context } from "../../contracts/TellerV2Context.sol"; import { IMarketRegistry } from "../../contracts/interfaces/IMarketRegistry.sol"; +import { IMarketRegistry_V2 } from "../../contracts/interfaces/IMarketRegistry_V2.sol"; contract TellerV2Context_Override is TellerV2Context { using EnumerableSet for EnumerableSet.AddressSet; @@ -12,7 +13,7 @@ contract TellerV2Context_Override is TellerV2Context { constructor(address _marketRegistry, address _lenderCommitmentForwarder) TellerV2Context(address(0)) { - marketRegistry = IMarketRegistry(_marketRegistry); + marketRegistry = IMarketRegistry_V2(_marketRegistry); lenderCommitmentForwarder = _lenderCommitmentForwarder; } diff --git a/packages/contracts/tests/Test_Helpers.sol b/packages/contracts/tests/Test_Helpers.sol index a37862157..8a06f6594 100644 --- a/packages/contracts/tests/Test_Helpers.sol +++ b/packages/contracts/tests/Test_Helpers.sol @@ -3,12 +3,12 @@ pragma solidity >=0.8.0 <0.9.0; import { TellerV2 } from "../contracts/TellerV2.sol"; import "../contracts/mock/WethMock.sol"; -import "../contracts/interfaces/IMarketRegistry.sol"; +import "../contracts/interfaces/IMarketRegistry_V2.sol"; import "../contracts/interfaces/ITellerV2.sol"; import "../contracts/interfaces/ITellerV2Context.sol"; import { Collateral } from "../contracts/interfaces/escrow/ICollateralEscrowV1.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { PaymentType } from "../contracts/libraries/V2Calculations.sol"; +import { PaymentType , PaymentCycleType } from "../contracts/libraries/V2Calculations.sol"; contract User { address public immutable tellerV2; @@ -25,7 +25,7 @@ contract User { IERC20(_assetContractAddress).approve(_spender, _amount); } - function createMarketSimple( + /*function createMarketSimple( address marketRegistry, uint32 _paymentCycleDuration, uint32 _paymentDefaultDuration, @@ -33,21 +33,33 @@ contract User { uint16 _feePercent, bool _requireLenderAttestation, bool _requireBorrowerAttestation, + PaymentType _paymentType, + PaymentCycleType _paymentCycleType, + address _feeRecipient, string calldata _uri - ) public returns (uint256) { + ) public returns (uint256,bytes32) { + + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:_paymentCycleDuration, + paymentDefaultDuration:_paymentDefaultDuration, + bidExpirationTime:_bidExpirationTime, + marketplaceFeePercent:_feePercent, + paymentType:_paymentType, + paymentCycleType:_paymentCycleType, + feeRecipient: address(_feeRecipient) + + }); + return - IMarketRegistry(marketRegistry).createMarket( - address(this), - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, + IMarketRegistry_V2(marketRegistry).createMarket( + address(this), _requireLenderAttestation, _requireBorrowerAttestation, - _uri + _uri, + marketTerms ); } - +*/ function createMarket( address marketRegistry, uint32 _paymentCycleDuration, @@ -58,20 +70,27 @@ contract User { bool _requireBorrowerAttestation, PaymentType _paymentType, PaymentCycleType _paymentCycleType, + address _feeRecipient, string calldata _uri - ) public returns (uint256) { + ) public returns (uint256,bytes32) { + IMarketRegistry_V2.MarketplaceTerms memory marketTerms = IMarketRegistry_V2.MarketplaceTerms({ + paymentCycleDuration:_paymentCycleDuration, + paymentDefaultDuration:_paymentDefaultDuration, + bidExpirationTime:_bidExpirationTime, + marketplaceFeePercent:_feePercent, + paymentType:_paymentType, + paymentCycleType:_paymentCycleType, + feeRecipient: address(_feeRecipient) + + }); + return - IMarketRegistry(marketRegistry).createMarket( - address(this), - _paymentCycleDuration, - _paymentDefaultDuration, - _bidExpirationTime, - _feePercent, + IMarketRegistry_V2(marketRegistry).createMarket( + address(this), _requireLenderAttestation, _requireBorrowerAttestation, - _paymentType, - _paymentCycleType, - _uri + _uri, + marketTerms ); } diff --git a/packages/contracts/tests/V2Calculations_Test.sol b/packages/contracts/tests/V2Calculations_Test.sol index 3cea8c873..00d0ca8ca 100644 --- a/packages/contracts/tests/V2Calculations_Test.sol +++ b/packages/contracts/tests/V2Calculations_Test.sol @@ -165,6 +165,8 @@ contract V2Calculations_Test is Testable { //need this here or else it defaults to EMI ! __bid.paymentType = _paymentType; + uint32 _paymentCycleDuration = __bid.terms.paymentCycle; + // Set the bid's payment cycle amount __bid.terms.paymentCycleAmount = paymentCycleAmount; // Set accepted bid timestamp to now @@ -188,7 +190,7 @@ contract V2Calculations_Test is Testable { uint256 duePrincipal; uint256 interest; (owedPrincipal, duePrincipal, interest) = V2Calculations - .calculateAmountOwed(__bid, nowTimestamp, _paymentCycleType); + .calculateAmountOwed(__bid, nowTimestamp, _paymentCycleType, _paymentCycleDuration); // Check if we should skip this cycle for payments if (cyclesToSkip.length() > 0) { @@ -258,7 +260,8 @@ contract V2Calculations_Test is Testable { __bid, 1658159355, // last repaid timestamp 1663189241, //timestamp - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + 2592000 ); assertEq( @@ -293,7 +296,8 @@ contract V2Calculations_Test is Testable { __bid, 2000000 + 3000, //last repaid timestamp 2000000 + 5500, //timestamp - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + 3000 ); assertEq(_owedPrincipal, 10000, "Expected owed principal incorrect"); @@ -318,7 +322,8 @@ contract V2Calculations_Test is Testable { __bid, 2000000 + 3000, //last repaid timestamp 2000000 + 7500, //timestamp - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + 3000 ); assertEq(_owedPrincipal, 10000, "Expected owed principal incorrect"); @@ -343,7 +348,8 @@ contract V2Calculations_Test is Testable { __bid, 2000000 + 3000, //last repaid timestamp 2000000 + 19500, //timestamp - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + 3000 ); assertEq(_owedPrincipal, 10000, "Expected owed principal incorrect"); @@ -385,7 +391,8 @@ contract V2Calculations_Test is Testable { __bid, _lastRepaidTimestamp, _timestamp, - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + 2592000 ); assertEq( @@ -415,7 +422,8 @@ contract V2Calculations_Test is Testable { __bid, _lastRepaidTimestamp, _timestamp, - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + __bid.terms.paymentCycle ); assertEq( @@ -438,7 +446,8 @@ contract V2Calculations_Test is Testable { __bid, _lastRepaidTimestamp, _timestamp, - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + __bid.terms.paymentCycle ); assertEq( @@ -465,7 +474,8 @@ contract V2Calculations_Test is Testable { __bid, _lastRepaidTimestamp, _timestamp, - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + __bid.terms.paymentCycle ); assertEq( @@ -522,7 +532,8 @@ contract V2Calculations_Test is Testable { __bid, _lastRepaidTimestamp, _timestamp, - PaymentCycleType.Seconds + PaymentCycleType.Seconds, + __bid.terms.paymentCycle ); assertEq( diff --git a/packages/contracts/tests/integration/IntegrationFork.sol b/packages/contracts/tests/integration/IntegrationFork.sol index 9d063835b..22a4af320 100644 --- a/packages/contracts/tests/integration/IntegrationFork.sol +++ b/packages/contracts/tests/integration/IntegrationFork.sol @@ -2,9 +2,12 @@ pragma solidity <0.9.0; pragma abicoder v2; import "../util/FoundryTest.sol"; -import { IMarketRegistry } from "../../contracts/interfaces/IMarketRegistry.sol"; +import { IMarketRegistry_V1 } from "../../contracts/interfaces/IMarketRegistry_V1.sol"; +import { IMarketRegistry_V2 } from "../../contracts/interfaces/IMarketRegistry_V2.sol"; import { ITellerV2 } from "../../contracts/interfaces/ITellerV2.sol"; +import { MarketRegistry } from "../../contracts/MarketRegistry.sol"; + import { ILenderCommitmentForwarder } from "../../contracts/interfaces/ILenderCommitmentForwarder.sol"; import { ITellerV2Storage } from "../../contracts/interfaces/ITellerV2Storage.sol"; @@ -17,7 +20,7 @@ import { ITellerV2Context } from "../../contracts/interfaces/ITellerV2Context.so contract IntegrationForkSetup is Test { ITellerV2 internal tellerV2; address collateralManagerV1; - IMarketRegistry internal marketRegistry; + IMarketRegistry_V1 internal marketRegistry; ILenderCommitmentForwarder internal commitmentForwarder; address lender; @@ -30,7 +33,7 @@ contract IntegrationForkSetup is Test { mapping(address => mapping(address => uint256)) internal commitmentsIds; function setUp() public virtual { - //when this LOC runs, all old vm state is deleted + //when this LOC runs, all old vm state is deleted // NOTE: must fork the network before calling super.setUp() uint256 mainnetFork = vm.createSelectFork("mainnet"); @@ -50,9 +53,11 @@ contract IntegrationForkSetup is Test { ); vm.label(address(tellerV2), "tellerV2"); - collateralManagerV1 = address( ITellerV2(address(tellerV2)).collateralManager() ); + collateralManagerV1 = address( + ITellerV2(address(tellerV2)).collateralManager() + ); - marketRegistry = IMarketRegistry( + marketRegistry = IMarketRegistry_V1( ITellerV2Storage(address(tellerV2)).marketRegistry() ); vm.label(address(marketRegistry), "marketRegistry"); @@ -74,6 +79,13 @@ contract IntegrationForkSetup is Test { PaymentCycleType.Seconds, // payment cycle type "" // metadata ); + + //simulate upgrading the market registry to v2 + address marketRegistry_V2_Impl = address(new MarketRegistry()); + vm.etch(address(marketRegistry), address(marketRegistry_V2_Impl).code); + + //need to re-create market by updating its settings + ITellerV2Context(address(tellerV2)).setTrustedMarketForwarder( marketId, address(commitmentForwarder) diff --git a/packages/contracts/tests/integration/IntegrationTestHelpers.sol b/packages/contracts/tests/integration/IntegrationTestHelpers.sol index 7815b87b9..2c082c49e 100644 --- a/packages/contracts/tests/integration/IntegrationTestHelpers.sol +++ b/packages/contracts/tests/integration/IntegrationTestHelpers.sol @@ -2,6 +2,7 @@ pragma solidity >=0.8.0 <0.9.0; // SPDX-License-Identifier: MIT import { TellerV2 } from "../../contracts/TellerV2.sol"; +import { PaymentType, PaymentCycleType } from "../../contracts/libraries/V2Calculations.sol"; import "../../contracts/EAS/TellerAS.sol"; import "../../contracts/EAS/TellerASEIP712Verifier.sol"; @@ -11,6 +12,9 @@ import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import { MarketRegistry } from "../../contracts/MarketRegistry.sol"; + +import { IMarketRegistry_V2 } from "../../contracts/interfaces/IMarketRegistry_V2.sol"; + import { EscrowVault } from "../../contracts/EscrowVault.sol"; import { LenderManager } from "../../contracts/LenderManager.sol"; //import { LenderCommitmentForwarder_G3 } from "../../contracts/LenderCommitmentForwarder/LenderCommitmentForwarder_G3.sol"; @@ -21,24 +25,12 @@ import { ReputationManager } from "../../contracts/ReputationManager.sol"; import { IMarketRegistry } from "../../contracts/interfaces/IMarketRegistry.sol"; library IntegrationTestHelpers { - function deployMarketRegistry() public returns (address) { - IASRegistry iasRegistry = new TellerASRegistry(); - IEASEIP712Verifier ieaseip712verifier = new TellerASEIP712Verifier(); - - TellerAS tellerAS = new TellerAS((iasRegistry), (ieaseip712verifier)); - MarketRegistry marketRegistry = new MarketRegistry(); - - marketRegistry.initialize(tellerAS); - - return address(marketRegistry); - } - function deployIntegrationSuite() public returns (TellerV2 tellerV2_) { address trustedForwarder = address(0); TellerV2 tellerV2 = new TellerV2(trustedForwarder); uint16 _protocolFee = 100; - address _marketRegistry = deployMarketRegistry(); + MarketRegistry _marketRegistry = new MarketRegistry(); ReputationManager _reputationManager = new ReputationManager(); /* diff --git a/packages/subgraph/README.md b/packages/subgraph/README.md index a0c3703d1..f2d897b73 100644 --- a/packages/subgraph/README.md +++ b/packages/subgraph/README.md @@ -63,4 +63,13 @@ yarn subgraph deploy-local:polygon 1. Build: yarn subgraph build goerli -2. Deploy: yarn subgraph build:deploy goerli \ No newline at end of file +2. Deploy: yarn subgraph build:deploy goerli + + +## Terminal CLI script + +1. yarn deploy:prompt + + #### notes + Choosing RELEASE will automatically deploy fresh without block handlers then will deploy grafting with block handlers + \ No newline at end of file diff --git a/packages/subgraph/config/goerli.json b/packages/subgraph/config/goerli.json index 3dac3f713..dfd450a7b 100644 --- a/packages/subgraph/config/goerli.json +++ b/packages/subgraph/config/goerli.json @@ -1 +1,57 @@ -{"enabled":true,"name":"tellerv2-goerli","network":"goerli","export_network_name":"goerli","product":"studio","studio":{"owner":"0x1A2bAA2257343119FB03FD448622456a0c4f2190","network":"mainnet"},"grafting":{"enabled":true,"base":"QmZmKH8889YSEsNTYUWyGQxc1iGtN14zcAZ3qNer1rbJ8f","block":9699870},"block_handler":{"enabled":true,"block":"8538452"},"contracts":{"teller_v2":{"enabled":true,"address":"0x195c6608705546725DF0629dd60690Cf2b367734","block":"8538452"},"market_registry":{"enabled":true,"address":"0x74FFC87282ab32c8E0969E26F93C820a213ae146","block":"8538442"},"lender_commitment":{"enabled":true,"address":"0xB1b668592A4FCA5d0Cd91D4E5D8b33cb95043E43","block":"8538455"},"collateral_manager":{"enabled":true,"address":"0xD66de8b25C4165dA2e7696e15E8436380823B118","block":"8538491"},"lender_manager":{"enabled":true,"address":"0x98Ca52786e967d1469090AdC075416948Ca004A7","block":"8538444"},"market_liquidity_rewards":{"enabled":true,"address":"0xfa0a79661ad21fbd416ddbD9a098564b3686adf5","block":"8667201"}}} \ No newline at end of file +{ + "enabled": true, + "name": "tellerv2-goerli", + "network": "goerli", + "export_network_name": "goerli", + "product": "studio", + "studio": { + "owner": "0x1A2bAA2257343119FB03FD448622456a0c4f2190", + "network": "mainnet" + }, + "grafting": { + "enabled": true, + "base": "QmZmKH8889YSEsNTYUWyGQxc1iGtN14zcAZ3qNer1rbJ8f", + "block": 9699870 + }, + "block_handler": { + "enabled": true, + "block": "8538452" + }, + "contracts": { + "teller_v2": { + "enabled": true, + "address": "0x195c6608705546725DF0629dd60690Cf2b367734", + "block": "8538452" + }, + "market_registry": { + "enabled": true, + "address": "0x74FFC87282ab32c8E0969E26F93C820a213ae146", + "block": "8538442" + }, + "lender_commitment": { + "enabled": true, + "address": "0xB1b668592A4FCA5d0Cd91D4E5D8b33cb95043E43", + "block": "8538455" + }, + "lender_commitment_staging": { + "enabled": true, + "address": "0x53C51EDCB0b6cdDA1A79461c22Ea710649B4775A", + "block": "9924312" + }, + "collateral_manager": { + "enabled": true, + "address": "0xD66de8b25C4165dA2e7696e15E8436380823B118", + "block": "8538491" + }, + "lender_manager": { + "enabled": true, + "address": "0x98Ca52786e967d1469090AdC075416948Ca004A7", + "block": "8538444" + }, + "market_liquidity_rewards": { + "enabled": true, + "address": "0xfa0a79661ad21fbd416ddbD9a098564b3686adf5", + "block": "8667201" + } + } +} \ No newline at end of file diff --git a/packages/subgraph/config/goerlitest.json b/packages/subgraph/config/goerlitest.json new file mode 100644 index 000000000..5834f118f --- /dev/null +++ b/packages/subgraph/config/goerlitest.json @@ -0,0 +1 @@ +{"enabled":true,"name":"tellerv2","network":"goerli","export_network_name":"goerli","product":"studio","studio":{"owner":"0x1a76339211668a6939e1d6D13AB902bBef5D9ebc","network":"arbitrum-one"},"grafting":{"enabled":false},"block_handler":{"enabled":false},"contracts":{"teller_v2":{"enabled":true,"address":"0x195c6608705546725DF0629dd60690Cf2b367734","block":"8538452"},"market_registry":{"enabled":true,"address":"0x74FFC87282ab32c8E0969E26F93C820a213ae146","block":"8538442"},"lender_commitment":{"enabled":true,"address":"0xB1b668592A4FCA5d0Cd91D4E5D8b33cb95043E43","block":"8538455"},"lender_commitment_staging":{"enabled":true,"address":"0x53C51EDCB0b6cdDA1A79461c22Ea710649B4775A","block":"9924312"},"collateral_manager":{"enabled":true,"address":"0xD66de8b25C4165dA2e7696e15E8436380823B118","block":"8538491"},"lender_manager":{"enabled":true,"address":"0x98Ca52786e967d1469090AdC075416948Ca004A7","block":"8538444"},"market_liquidity_rewards":{"enabled":true,"address":"0xfa0a79661ad21fbd416ddbD9a098564b3686adf5","block":"8667201"}}} \ No newline at end of file diff --git a/packages/subgraph/package.json b/packages/subgraph/package.json index b98327eb7..095719c2b 100644 --- a/packages/subgraph/package.json +++ b/packages/subgraph/package.json @@ -1,7 +1,7 @@ { "name": "@teller-protocol/v2-subgraph", "license": "UNLICENSED", - "version": "0.4.21-4", + "version": "0.4.21-6", "scripts": { "deploy:prompt": "ts-node scripts/thegraph", "create-local": "graph create --node http://localhost:8020/ teller-v2", diff --git a/packages/subgraph/scripts/thegraph/api/config/readme.md b/packages/subgraph/scripts/thegraph/api/config/readme.md new file mode 100644 index 000000000..1634a166c --- /dev/null +++ b/packages/subgraph/scripts/thegraph/api/config/readme.md @@ -0,0 +1,20 @@ + +### How to use this folder + + + +#### Example studio.json file in this folder + +{ + "0x1a76339211668a6939e1d6D13AB902bBef5D9ebc": { <---- public key of gnosis safe wallet + "deployKey":"1384...7294e81ae" <--- deploy key from subgraph studio page , + "network": "mainnet" | "arbitrum-one" + } + +} + + +#### notes + +The scripts should add a cookie 'Cookie' to the object above . It is an access token. +This is used to the graphs websocket api. diff --git a/packages/subgraph/scripts/thegraph/api/studio.ts b/packages/subgraph/scripts/thegraph/api/studio.ts index d88f3d53b..be4875e29 100644 --- a/packages/subgraph/scripts/thegraph/api/studio.ts +++ b/packages/subgraph/scripts/thegraph/api/studio.ts @@ -32,6 +32,9 @@ const Network: Record = { "arbitrum-one": 42161 }; +const ENABLE_COOKIE = false; + + export const makeStudio = async ( networkConfig: INetworkConfig ): Promise => { @@ -118,18 +121,24 @@ export const makeStudio = async ( if (!socket.isConnected()) await socket.connect(); let cookie: string | null = null; - // const Cookie = studioConfig[networkConfig.owner.address]?.Cookie; - // if (Cookie) { - // if (new Date(Cookie.expiration).getTime() > Date.now()) { - // cookie = Cookie.value; - // } else { - // networkConfig.logger?.log("Cookie expired, logging in again"); - // } - // } else { - // networkConfig.logger?.log( - // "Not logged in, attempting to log in via ledger..." - // ); - // } + + if (ENABLE_COOKIE) { + + const existingCookie = studioConfig[networkConfig.owner.address]?.Cookie; + if (existingCookie) { + if (new Date(existingCookie.expiration).getTime() > Date.now()) { + cookie = existingCookie.value; + } else { + networkConfig.logger?.log("Cookie expired, logging in again"); + } + } else { + networkConfig.logger?.log( + "Not logged in, attempting to log in via ledger..." + ); + } + + } + if (!cookie) { const transport = await Transport.open("");