Address Contract Partially Verified
Address
0xbAD003DA1e107f537Ae2f687f5FE7a7aFFe9B241
Balance
0 ETH
Nonce
1
Code Size
15013 bytes
Creator
0x87c9b9CE...adeA at tx 0x3786164f...104591
Indexed Transactions
0
Contract Bytecode
15013 bytes
0x608060405234801561001057600080fd5b50600436106101c45760003560e01c80635c60da1b116100f9578063c45a015511610097578063dac83f8d11610071578063dac83f8d146104b1578063dc4c90d3146104c4578063f6de0bd2146104d7578063ffb43a5f146104df57600080fd5b8063c45a015514610483578063d784d4261461048b578063d97aea121461049e57600080fd5b80639e5d9942116100d35780639e5d994214610437578063aaf5eb681461044a578063ac6416551461045d578063c3fbb6fd1461047057600080fd5b80635c60da1b146103f357806367e2ba23146103fb5780636ed93dd01461042d57600080fd5b806339ba9f861161016657806340504ba01161014057806340504ba0146103395780634189182e1461036957806345fe329f146103b9578063546ef145146103c157600080fd5b806339ba9f86146102e45780633b99bcee1461030f5780633c9ae2ba1461032257600080fd5b80631cd8d07b116101a25780631cd8d07b1461029857806320d61476146102ab57806323024408146102be57806337fdb36f146102d157600080fd5b80630827b071146101c957806309be15e0146101de578063165b0a9c14610271575b600080fd5b6101dc6101d73660046135bf565b610507565b005b6102306101ec3660046133ee565b60076020526000908152604090205462ffffff808216916301000000810490911690600160301b810464ffffffffff1690600160581b90046001600160a81b031684565b6040805162ffffff958616815294909316602085015264ffffffffff909116918301919091526001600160a81b031660608201526080015b60405180910390f35b6001546102829064ffffffffff1681565b60405164ffffffffff9091168152602001610268565b6101dc6102a63660046133ee565b6108df565b6101dc6102b93660046133ee565b610a6e565b6101dc6102cc3660046133ee565b610b97565b6101dc6102df366004613461565b611101565b6004546102f7906001600160a01b031681565b6040516001600160a01b039091168152602001610268565b6101dc61031d36600461360c565b6111a8565b61032b60035481565b604051908152602001610268565b61034c610347366004613428565b61147e565b604080519315158452602084019290925290820152606001610268565b61039c6103773660046133ee565b60066020526000908152604090205464ffffffffff811690600160281b900460ff1682565b6040805164ffffffffff9093168352901515602083015201610268565b61032b61149a565b6001546103db90600160281b90046001600160701b031681565b6040516001600160701b039091168152602001610268565b6102f76114ce565b60025461041590600160801b90046001600160801b031681565b6040516001600160801b039091168152602001610268565b61032b620f424081565b6101dc6104453660046133ee565b6114dd565b61032b6b033b2e3c9fd0803ce800000081565b600254610415906001600160801b031681565b6101dc61047e366004613503565b611569565b6102f7611611565b6101dc6104993660046133ee565b61161b565b6101dc6104ac366004613558565b6116b0565b6101dc6104bf366004613461565b61170b565b6005546102f7906001600160a01b031681565b61032b611757565b6104f26104ed3660046133ee565b61179d565b60408051928352602083019190915201610268565b61050f611a6c565b3361051981611b34565b60005460011461055c5760405162461bcd60e51b815260206004820152600960248201526813134e9313d0d2d15160ba1b60448201526064015b60405180910390fd5b60026000819055506000336001600160a01b031663ba5d30786040518163ffffffff1660e01b815260040160206040518083038186803b15801561059f57600080fd5b505afa1580156105b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d791906135a6565b905060008364ffffffffff161180156105f05750600081115b80610615575064ffffffffff8316158015610609575080155b80156106155750600087135b6106505760405162461bcd60e51b815260206004820152600c60248201526b13134e90ce9253959053125160a21b6044820152606401610553565b60008761065c83611b98565b61066691906138d3565b90506106723382611bf5565b50506106813389898989611d2f565b87156106985761069861069389613a14565b612009565b60006106a33361209d565b905060006106dc6106d783606001516001600160a81b0316846040015164ffffffffff16426106d291906139d7565b61215a565b611b98565b6106e590613a14565b905064ffffffffff86166107245761071b8161070d84606001516001600160a81b0316611b98565b61071690613a14565b612184565b505050506108d2565b60008a1215610885576000336001600160a01b0316637df1f1b96040518163ffffffff1660e01b815260040160206040518083038186803b15801561076857600080fd5b505afa15801561077c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a0919061340b565b90506107aa61226f565b60405163eaf6e48360e01b81526001600160a01b038381166004830152919091169063eaf6e4839060240160206040518083038186803b1580156107ed57600080fd5b505afa158015610801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108259190613584565b6108695760405162461bcd60e51b815260206004820152601560248201527426269d219d24a72b20a624a22fa127a92927aba2a960591b6044820152606401610553565b6108833361087e6108798e613a14565b6122e9565b61233b565b505b6000610890336123fc565b90506108cc826108ac85606001516001600160a81b0316611b98565b6108c284606001516001600160a81b0316611b98565b6107169190613998565b50505050505b5050600160005550505050565b6108e7611a6c565b806108f181611b34565b600061096d83846001600160a01b031663ba5d30786040518163ffffffff1660e01b815260040160206040518083038186803b15801561093057600080fd5b505afa158015610944573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096891906135a6565b611bf5565b915050610978612753565b6001600160a01b0316336001600160a01b031614806109b85750801580156109b857506109a3612795565b6001600160a01b0316336001600160a01b0316145b6109f55760405162461bcd60e51b815260206004820152600e60248201526d0989a74a49892749c9ebe82aaa8960931b6044820152606401610553565b826001600160a01b03166365cd0a4c6040518163ffffffff1660e01b81526004016040805180830381600087803b158015610a2f57600080fd5b505af1158015610a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6791906136df565b5050505050565b610a76611a6c565b80610a8081611b34565b6000610a8a612753565b6001600160a01b0316336001600160a01b03161490508080610ac45750610aaf612795565b6001600160a01b0316336001600160a01b0316145b610b005760405162461bcd60e51b815260206004820152600d60248201526c0989a749298749c9ebe82aaa89609b1b6044820152606401610553565b826001600160a01b0316630548d2676040518163ffffffff1660e01b81526004016040805180830381600087803b158015610b3a57600080fd5b505af1158015610b4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7291906136df565b50508015610b8957610b83836127da565b50505050565b610b83836127ed565b505050565b610b9f611a6c565b600054600114610bdd5760405162461bcd60e51b815260206004820152600960248201526813134e9313d0d2d15160ba1b6044820152606401610553565b6002600055610bea6127fa565b6000816001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610c2557600080fd5b505afa158015610c39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5d919061340b565b90506000610c6961226f565b60405163305c9e0560e01b81526e4f545f4c4f414e5f464143544f525960881b60048201526001600160a01b0384811660248301529192509082169063305c9e059060440160206040518083038186803b158015610cc657600080fd5b505afa158015610cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfe9190613584565b610d4a5760405162461bcd60e51b815260206004820152601960248201527f4c4d3a463a494e56414c49445f4c4f414e5f464143544f5259000000000000006044820152606401610553565b60405163140ce5e160e11b81526001600160a01b038481166004830152831690632819cbc29060240160206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc39190613584565b610e0f5760405162461bcd60e51b815260206004820152601a60248201527f4c4d3a463a494e56414c49445f4c4f414e5f494e5354414e43450000000000006044820152606401610553565b806001600160a01b031663eaf6e483846001600160a01b0316637df1f1b96040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5757600080fd5b505afa158015610e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8f919061340b565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015610ece57600080fd5b505afa158015610ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f069190613584565b610f4a5760405162461bcd60e51b815260206004820152601560248201527426269d231d24a72b20a624a22fa127a92927aba2a960591b6044820152606401610553565b6000836001600160a01b031663ba5d30786040518163ffffffff1660e01b815260040160206040518083038186803b158015610f8557600080fd5b505afa158015610f99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbd91906135a6565b9050806110035760405162461bcd60e51b81526020600482015260146024820152734c4d3a463a4c4f414e5f4e4f545f41435449564560601b6044820152606401610553565b61100d848261233b565b6000846001600160a01b031663b60d42886040518163ffffffff1660e01b8152600401606060405180830381600087803b15801561104a57600080fd5b505af115801561105e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611082919061367f565b505090508181146110cd5760405162461bcd60e51b81526020600482015260156024820152740989a748c748caa9c88929c8ebe9a92a69a82a8869605b1b6044820152606401610553565b6110d961069382611b98565b60006110e4866123fc565b90506108d2600061071683606001516001600160a81b0316611b98565b611109611a6c565b6111116127fa565b8461111b81611b34565b604051632b2d48ad60e21b81526001600160a01b0387169063acb522b49061114d908890889088908890600401613804565b602060405180830381600087803b15801561116757600080fd5b505af115801561117b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119f91906135a6565b50505050505050565b6111b0611a6c565b60006111ba61226f565b90506111c4612795565b6001600160a01b0316336001600160a01b031614156113145760405163fd4c5b3760e01b81526001600160a01b0382169063fd4c5b379061121090339030906000903690600401613782565b60206040518083038186803b15801561122857600080fd5b505afa15801561123c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190613584565b6112ac5760405162461bcd60e51b815260206004820152601760248201527f4c4d3a553a494e56414c49445f53434845445f43414c4c0000000000000000006044820152606401610553565b604051635ad5b6f760e11b81526001600160a01b0382169063b5ab6dee906112dd90339060009036906004016137cc565b600060405180830381600087803b1580156112f757600080fd5b505af115801561130b573d6000803e3d6000fd5b505050506113d4565b806001600160a01b031663be7c13f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561134d57600080fd5b505afa158015611361573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611385919061340b565b6001600160a01b0316336001600160a01b0316146113d45760405162461bcd60e51b815260206004820152600c60248201526b0989a74aa749c9ebe82aaa8960a31b6044820152606401610553565b7faaaa7ee6b0c2f4ee1fa7312c7d5b3623a434da5a1a9ce3cb6e629caa23454ab6848484604051611407939291906138b9565b60405180910390a161141761284e565b6001600160a01b031663fe69f7088585856040518463ffffffff1660e01b8152600401611446939291906138b9565b600060405180830381600087803b15801561146057600080fd5b505af1158015611474573d6000803e3d6000fd5b5050505050505050565b600080600061148c8561179d565b600197919650945092505050565b60035460009080156114c5576001546114c09082906106d29064ffffffffff16426139d7565b6114c8565b60005b91505090565b60006114d861287d565b905090565b6114e5611a6c565b6114ed6127fa565b806114f781611b34565b816001600160a01b031663200e53456040518163ffffffff1660e01b81526004016040805180830381600087803b15801561153157600080fd5b505af1158015611545573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8391906136df565b611571611a6c565b61157961284e565b6001600160a01b0316336001600160a01b0316146115cc5760405162461bcd60e51b815260206004820152601060248201526f4c4d3a4d3a4e4f545f464143544f525960801b6044820152606401610553565b6115d78383836128a7565b610b925760405162461bcd60e51b815260206004820152600b60248201526a13134e934e91905253115160aa1b6044820152606401610553565b60006114d861284e565b611623611a6c565b61162b61284e565b6001600160a01b0316336001600160a01b03161461167f5760405162461bcd60e51b81526020600482015260116024820152704c4d3a53493a4e4f545f464143544f525960781b6044820152606401610553565b6001600160a01b03167f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b5050565b6116b8611a6c565b6116c06127fa565b816116ca81611b34565b604051630c7341dd60e31b8152600481018390526001600160a01b0384169063639a0ee8906024016040805180830381600087803b158015610a2f57600080fd5b611713611a6c565b61171b6127fa565b8461172581611b34565b6040516387accaf160e01b81526001600160a01b038716906387accaf19061114d908890889088908890600401613804565b600061176161149a565b60015460025461178a91600160281b90046001600160701b0316906001600160801b0316613914565b6001600160801b03166114d8919061393f565b6000806117a8611a6c565b826117b281611b34565b6005546001600160a01b031633146117fb5760405162461bcd60e51b815260206004820152600c60248201526b4c4d3a54443a4e4f545f504d60a01b6044820152606401610553565b6000611806856127ed565b604051630938afdd60e41b815264ffffffffff82166004820152909150600090819081906001600160a01b0389169063938afdd09060240160a06040518083038186803b15801561185657600080fd5b505afa15801561186a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188e919061363f565b94505093509350506000886001600160a01b031663ba5d30786040518163ffffffff1660e01b815260040160206040518083038186803b1580156118d157600080fd5b505afa1580156118e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190991906135a6565b9050611915838561393f565b6040516347350e9f60e01b81523060048201529094506000906001600160a01b038b16906347350e9f90602401602060405180830381600087803b15801561195c57600080fd5b505af1158015611970573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199491906135a6565b90506119a38a83878685612920565b909950975060006119b38b61209d565b905060006119e482606001516001600160a81b031683604001518a6119d891906139ee565b64ffffffffff1661215a565b9050611a026119f282611b98565b6119fb90613a14565b6000612184565b611a20611a126106d7838761393f565b611a1b90613a14565b612c79565b611a35611a2c85611b98565b61069390613a14565b5050506001600160a01b039098166000908152600660205260409020805465ffffffffffff19169055509496939550929350505050565b611a7461226f565b604051634c532de160e01b81526001600160e01b03196000351660048201526001600160a01b039190911690634c532de19060240160206040518083038186803b158015611ac157600080fd5b505afa158015611ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af99190613584565b15611b325760405162461bcd60e51b815260206004820152600960248201526813134e94105554d15160ba1b6044820152606401610553565b565b6001600160a01b038116600090815260076020526040902054600160301b900464ffffffffff16611b955760405162461bcd60e51b815260206004820152600b60248201526a26269d2727aa2fa627a0a760a91b6044820152606401610553565b50565b60006001600160ff1b03821115611bf15760405162461bcd60e51b815260206004820152601960248201527f4c4d3a55494e543235365f4f4f425f464f525f494e54323536000000000000006044820152606401610553565b5090565b6001600160a01b03821660009081526006602090815260409182902082518084019093525464ffffffffff8116808452600160281b90910460ff1615159183018290529182611c445750611d28565b6001600160a01b0385166000908152600660209081526040808320805465ffffffffffff1916905560078252918290208251608081018452905462ffffff808216835263010000008204169282019290925264ffffffffff600160301b830416928101839052600160581b9091046001600160a81b0316606082018190529091611ce591611a1291611cdb91906119d890896139ee565b6106d7908861393f565b611d25611d0f6106d783606001516001600160a81b03168764ffffffffff16426106d291906139d7565b61071683606001516001600160a81b0316611b98565b50505b9250929050565b6001600160a01b03851660009081526007602090815260408083208151608081018352905462ffffff80821683526301000000820416938201849052600160301b810464ffffffffff1692820192909252600160581b9091046001600160a81b031660608201529190611da3908690612cf4565b90506000611dba86846000015162ffffff16612cf4565b9050600560009054906101000a90046001600160a01b03166001600160a01b031663caf901dd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e0a57600080fd5b505afa158015611e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e429190613584565b611e5b57611e50858561393f565b935060009450600091505b6000611e67838361393f565b611e7190886139d7565b905060008813611e82576000611e84565b875b60408051828152602081018a9052908101859052606081018890526080810184905260a081018790529098506001600160a01b038a16907f5a3aaae9941b918d74569012f48c308c4044705e7ece73e7834f0f7ffd938b859060c00160405180910390a26004546001600160a01b0316611f0f81611f00612d04565b611f0a858d61393f565b612d49565b611f4f5760405162461bcd60e51b815260206004820152601160248201527004c4d3a4443463a5452414e534645525f5607c1b6044820152606401610553565b611f6581611f5b612795565b611f0a878b61393f565b611fa65760405162461bcd60e51b815260206004820152601260248201527113134e9110d18e9514905394d1915497d41160721b6044820152606401610553565b611fbc81611fb2612d79565b611f0a868a61393f565b611ffd5760405162461bcd60e51b815260206004820152601260248201527113134e9110d18e9514905394d1915497d35560721b6044820152606401610553565b50505050505050505050565b6002547f8e82b75967acb8b37df8c3edc1ef9712a6c32f8a42dbbd441f49be7cab41aee2906120609061205b90849061204a906001600160801b0316611b98565b61205491906138d3565b6000612dbb565b612dd1565b600280546fffffffffffffffffffffffffffffffff19166001600160801b039290921691821790556040519081526020015b60405180910390a150565b604080516080810182526000808252602082018190529181018290526060810191909152506001600160a01b03811660008181526007602081815260408084208151608081018352815462ffffff8082168352630100000082041682860152600160301b810464ffffffffff1682850152600160581b90046001600160a81b031660608201528686529390925290839055519092917f98e0ae8c0ac21cdd4b0a6a2c72737be54e995c54f6ef61b3cd19ec71ed22533b91a2919050565b60006b033b2e3c9fd0803ce80000006121738385613979565b61217d9190613957565b9392505050565b6121b86121b38361204a61219661149a565b6001546106d79190600160281b90046001600160701b031661393f565b612e37565b600160056101000a8154816001600160701b0302191690836001600160701b031602179055506121e742612e9d565b600160006101000a81548164ffffffffff021916908364ffffffffff16021790555061221b6108798261204a600354611b98565b600381905560015460408051928352600160281b9091046001600160701b031660208301527f1e2d80f327730eb6faf6e0ed856016385059a20185b280cb5293a05883ee6f81910160405180910390a15050565b600061227961284e565b6001600160a01b0316633a60339a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156122b157600080fd5b505afa1580156122c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d8919061340b565b600080821215611bf15760405162461bcd60e51b815260206004820152601960248201527f4c4d3a494e543235365f4f4f425f464f525f55494e54323536000000000000006044820152606401610553565b6005546040516324a3335b60e11b8152306004820152602481018390526001600160a01b039091169063494666b690604401600060405180830381600087803b15801561238757600080fd5b505af115801561239b573d6000803e3d6000fd5b50506004546123b792506001600160a01b031690508383612ef4565b6116ac5760405162461bcd60e51b815260206004820152601660248201527513134e941191930e9054141493d59157d1905253115160521b6044820152606401610553565b60408051608081018252600080825260208201819052918101829052606081018290529061242861226f565b600554604051631b14131d60e11b81526001600160a01b039182166004820152911690633628263a9060240160206040518083038186803b15801561246c57600080fd5b505afa158015612480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a491906135a6565b90506000600560009054906101000a90046001600160a01b03166001600160a01b0316635dd284496040518163ffffffff1660e01b815260040160206040518083038186803b1580156124f657600080fd5b505afa15801561250a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061252e91906135a6565b9050600061253c828461393f565b9050620f424081111561255f5761255683620f42406139d7565b9150620f424090505b6000856001600160a01b031663d9ef04596040518163ffffffff1660e01b815260040160206040518083038186803b15801561259a57600080fd5b505afa1580156125ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d291906136c2565b64ffffffffff16905060006125e8878385612fa3565b905060006125f642846139d7565b61260c6b033b2e3c9fd0803ce800000084613979565b6126169190613957565b9050604051806080016040528061262c88613039565b62ffffff16815260200161263f87613039565b62ffffff16815260200161265242612e9d565b64ffffffffff1681526020016126678361308e565b6001600160a81b039081169091526001600160a01b038a166000818152600760209081526040918290208551815487840151888601516060808b0151909916600160581b026affffffffffffffffffffff64ffffffffff909216600160301b029190911665ffffffffffff62ffffff93841663010000000265ffffffffffff19909516939095169290921792909217929092169190911717905581518b81529081018a90529081018790529182018490529198507f948106bee3c901826daa4428037840a48300999c9a8911510b1beb56f2dc02769060800160405180910390a2505050505050919050565b600061275d61226f565b6001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156122b157600080fd5b60055460408051634046af2b60e01b815290516000926001600160a01b031691634046af2b916004808301926020929190829003018186803b1580156122b157600080fd5b60006127e78260016130e7565b92915050565b60006127e78260006130e7565b612802612795565b6001600160a01b0316336001600160a01b031614611b325760405162461bcd60e51b815260206004820152600960248201526813134e9393d517d41160ba1b6044820152606401610553565b60006128787f7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af15490565b919050565b60006128787f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6000833b806128ba57600091505061217d565b846001600160a01b031684846040516128d4929190613737565b600060405180830381855af49150503d806000811461290f576040519150601f19603f3d011682016040523d82523d6000602084013e612914565b606091505b50909695505050505050565b6001600160a01b03851660009081526007602090815260408083208151608081018352905462ffffff8082168084526301000000830490911694830194909452600160301b810464ffffffffff1692820192909252600160581b9091046001600160a81b031660608201528291829061299a908890612cf4565b905060006129b188846020015162ffffff16612cf4565b905060006129bf828461393f565b6129c9908a6139d7565b905060006129d7848a61393f565b905060006129e589836132b4565b90506129f181836139d7565b96506129fd818a6139d7565b98506000612a168a858f612a11919061393f565b6132b4565b905080612a23858f61393f565b612a2d91906139d7565b9850612a39818b6139d7565b604080518f815260208101879052908101889052606081018d9052909a506001600160a01b038f16907fd6c35cb94fcd8788f1d1e61f1f635e83b26421b57c5db5bb71b275e41588be249060800160405180910390a2604080518b8152602081018390529081018390526001600160a01b038f16907f6fe470ca125c8e736c97af4412c288b2a0417f3f146625f3ff2280449b1e7a8b9060600160405180910390a2612b6b600460009054906101000a90046001600160a01b03168f6001600160a01b0316637df1f1b96040518163ffffffff1660e01b815260040160206040518083038186803b158015612b2d57600080fd5b505afa158015612b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b65919061340b565b8c612d49565b612bab5760405162461bcd60e51b815260206004820152601160248201527026269d2226231d2a2920a729a322a92fa160791b6044820152606401610553565b600454612bc9906001600160a01b0316612bc3612d04565b83612d49565b612c095760405162461bcd60e51b815260206004820152601160248201527004c4d3a444c463a5452414e534645525f5607c1b6044820152606401610553565b600454612c27906001600160a01b0316612c21612d79565b84612d49565b612c685760405162461bcd60e51b815260206004820152601260248201527113134e9113118e9514905394d1915497d35560721b6044820152606401610553565b505050505050509550959350505050565b7fa6fdea32383e711b89178e80732f32dd09a53fe2cfc2f613a7e5035de5e0bef6612cc861205b8361204a600260109054906101000a90046001600160801b03166001600160801b0316611b98565b600280546001600160801b03908116600160801b93909116928302179055604051908152602001612092565b6000620f42406121738385613979565b600554604080516316f0115b60e01b815290516000926001600160a01b0316916316f0115b916004808301926020929190829003018186803b1580156122b157600080fd5b60006001600160a01b03831615801590612d715750811580612d715750612d718484846132c3565b949350505050565b6000612d8361226f565b6001600160a01b031663a5a276056040518163ffffffff1660e01b815260040160206040518083038186803b1580156122b157600080fd5b6000818313612dca578161217d565b5090919050565b60006001600160801b038213801590612deb575060008212155b611bf15760405162461bcd60e51b815260206004820152601960248201527f4c4d3a494e543235365f4f4f425f464f525f55494e54313238000000000000006044820152606401610553565b60006001600160701b038213801590612e51575060008212155b611bf15760405162461bcd60e51b815260206004820152601960248201527f4c4d3a494e543235365f4f4f425f464f525f55494e54313132000000000000006044820152606401610553565b600064ffffffffff821115611bf15760405162461bcd60e51b815260206004820152601960248201527f4c4d3a55494e543235365f4f4f425f464f525f55494e543430000000000000006044820152606401610553565b6040516001600160a01b038316602482015260006044820181905290612f5a90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526132f6565b612f665750600061217d565b81612f735750600161217d565b6040516001600160a01b038416602482015260448101839052612d7190859063095ea7b360e01b90606401612f23565b604051630938afdd60e41b81526004810183905260009081906001600160a01b0386169063938afdd09060240160a06040518083038186803b158015612fe857600080fd5b505afa158015612ffc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613020919061363f565b5050509150506130308184613396565b95945050505050565b600062ffffff821115611bf15760405162461bcd60e51b815260206004820152601960248201527f4c4d3a55494e543235365f4f4f425f464f525f55494e543234000000000000006044820152606401610553565b60006001600160a81b03821115611bf15760405162461bcd60e51b815260206004820152601a60248201527f4c4d3a55494e543235365f4f4f425f464f525f55494e543136380000000000006044820152606401610553565b6001600160a01b03821660009081526006602052604090205464ffffffffff168015613112576127e7565b6001600160a01b0383166000908152600760209081526040918290208251608081018452905462ffffff8082168352630100000082041692820192909252600160301b820464ffffffffff1681840152600160581b9091046001600160a81b031660608201528151808301909252908061318b42612e9d565b64ffffffffff80821683528615156020938401526001600160a01b038816600090815260068452604081208551815496909501511515600160281b0265ffffffffffff1990961694909216939093179390931790925560608301519193506131ff9161070d906001600160a81b0316611b98565b6000846001600160a01b031663ba5d30786040518163ffffffff1660e01b815260040160206040518083038186803b15801561323a57600080fd5b505afa15801561324e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327291906135a6565b90506132ac611a1b6132a284606001516001600160a81b0316856040015164ffffffffff16426106d291906139d7565b6106d7908461393f565b505092915050565b6000818310612dca578161217d565b6040516001600160a01b038316602482015260448101829052600090612d7190859063a9059cbb60e01b90606401612f23565b60006001600160a01b0383163b61330f575060006127e7565b6060836001600160a01b0316836040516133299190613747565b6000604051808303816000865af19150503d8060008114613366576040519150601f19603f3d011682016040523d82523d6000602084013e61336b565b606091505b509092509050818015612d71575080511580612d71575080806020019051810190612d719190613584565b60006133a28383612cf4565b61217d90846139d7565b60008083601f8401126133be57600080fd5b50813567ffffffffffffffff8111156133d657600080fd5b602083019150836020828501011115611d2857600080fd5b60006020828403121561340057600080fd5b813561217d81613a47565b60006020828403121561341d57600080fd5b815161217d81613a47565b6000806040838503121561343b57600080fd5b823561344681613a47565b9150602083013561345681613a47565b809150509250929050565b60008060008060006080868803121561347957600080fd5b853561348481613a47565b9450602086013561349481613a47565b935060408601359250606086013567ffffffffffffffff808211156134b857600080fd5b818801915088601f8301126134cc57600080fd5b8135818111156134db57600080fd5b8960208260051b85010111156134f057600080fd5b9699959850939650602001949392505050565b60008060006040848603121561351857600080fd5b833561352381613a47565b9250602084013567ffffffffffffffff81111561353f57600080fd5b61354b868287016133ac565b9497909650939450505050565b6000806040838503121561356b57600080fd5b823561357681613a47565b946020939093013593505050565b60006020828403121561359657600080fd5b8151801515811461217d57600080fd5b6000602082840312156135b857600080fd5b5051919050565b600080600080600060a086880312156135d757600080fd5b8535945060208601359350604086013592506060860135915060808601356135fe81613a5c565b809150509295509295909350565b60008060006040848603121561362157600080fd5b83359250602084013567ffffffffffffffff81111561353f57600080fd5b600080600080600060a0868803121561365757600080fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b60008060006060848603121561369457600080fd5b8351925060208401516136a681613a5c565b60408501519092506136b781613a5c565b809150509250925092565b6000602082840312156136d457600080fd5b815161217d81613a5c565b600080604083850312156136f257600080fd5b82516136fd81613a5c565b602084015190925061345681613a5c565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8183823760009101908152919050565b6000825160005b81811015613768576020818601810151858301520161374e565b81811115613777576000828501525b509190910192915050565b6001600160a01b03858116825284166020820152694c4d3a5550475241444560b01b60408201526080606082018190526000906137c2908301848661370e565b9695505050505050565b6001600160a01b0384168152694c4d3a5550475241444560b01b6020820152606060408201819052600090613030908301848661370e565b6001600160a01b0385168152602080820185905260606040830181905282018390526000906080600585901b840181019190840186845b878110156138aa57868503607f190183528135368a9003601e1901811261386157600080fd5b8901803567ffffffffffffffff81111561387a57600080fd5b8036038b131561388957600080fd5b613896878288850161370e565b96505050918301919083019060010161383b565b50929998505050505050505050565b83815260406020820152600061303060408301848661370e565b600080821280156001600160ff1b03849003851316156138f5576138f5613a31565b600160ff1b839003841281161561390e5761390e613a31565b50500190565b60006001600160801b0380831681851680830382111561393657613936613a31565b01949350505050565b6000821982111561395257613952613a31565b500190565b60008261397457634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561399357613993613a31565b500290565b60008083128015600160ff1b8501841216156139b6576139b6613a31565b6001600160ff1b03840183138116156139d1576139d1613a31565b50500390565b6000828210156139e9576139e9613a31565b500390565b600064ffffffffff83811690831681811015613a0c57613a0c613a31565b039392505050565b6000600160ff1b821415613a2a57613a2a613a31565b5060000390565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b0381168114611b9557600080fd5b64ffffffffff81168114611b9557600080fdfea2646970667358221220688db322fbb27c42a3319d07e951e68b121e403abc92ae93a9d52b35b023332964736f6c63430008070033
Verified Source Code Partial Match
Compiler: v0.8.7+commit.e28d00a7
EVM: london
Optimization: Yes (200 runs)
LoanManager.sol 643 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.7;
import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol";
import { IMapleProxyFactory } from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxyFactory.sol";
import { MapleProxiedInternals } from "../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol";
import { ILoanManager } from "./interfaces/ILoanManager.sol";
import { IGlobalsLike, ILoanFactoryLike, ILoanLike, IPoolManagerLike } from "./interfaces/Interfaces.sol";
import { LoanManagerStorage } from "./LoanManagerStorage.sol";
/*
██╗ ██████╗ █████╗ ███╗ ██╗ ███╗ ███╗ █████╗ ███╗ ██╗ █████╗ ██████╗ ███████╗██████╗
██║ ██╔═══██╗██╔══██╗████╗ ██║ ████╗ ████║██╔══██╗████╗ ██║██╔══██╗██╔════╝ ██╔════╝██╔══██╗
██║ ██║ ██║███████║██╔██╗ ██║ ██╔████╔██║███████║██╔██╗ ██║███████║██║ ███╗█████╗ ██████╔╝
██║ ██║ ██║██╔══██║██║╚██╗██║ ██║╚██╔╝██║██╔══██║██║╚██╗██║██╔══██║██║ ██║██╔══╝ ██╔══██╗
███████╗╚██████╔╝██║ ██║██║ ╚████║ ██║ ╚═╝ ██║██║ ██║██║ ╚████║██║ ██║╚██████╔╝███████╗██║ ██║
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝
*/
contract LoanManager is ILoanManager, MapleProxiedInternals, LoanManagerStorage {
uint256 public override constant HUNDRED_PERCENT = 1e6; // 100.0000%
uint256 public override constant PRECISION = 1e27;
/**************************************************************************************************************************************/
/*** Modifiers ***/
/**************************************************************************************************************************************/
modifier isLoan(address loan_) {
_revertIfNotLoan(loan_);
_;
}
modifier nonReentrant() {
require(_locked == 1, "LM:LOCKED");
_locked = 2;
_;
_locked = 1;
}
modifier onlyPoolDelegate() {
_revertIfNotPoolDelegate();
_;
}
modifier whenNotPaused() {
_revertIfPaused();
_;
}
/**************************************************************************************************************************************/
/*** Upgradeability Functions ***/
/**************************************************************************************************************************************/
function migrate(address migrator_, bytes calldata arguments_) external override whenNotPaused {
require(msg.sender == _factory(), "LM:M:NOT_FACTORY");
require(_migrate(migrator_, arguments_), "LM:M:FAILED");
}
function setImplementation(address implementation_) external override whenNotPaused {
require(msg.sender == _factory(), "LM:SI:NOT_FACTORY");
_setImplementation(implementation_);
}
function upgrade(uint256 version_, bytes calldata arguments_) external override whenNotPaused {
IGlobalsLike globals_ = IGlobalsLike(_globals());
if (msg.sender == _poolDelegate()) {
require(globals_.isValidScheduledCall(msg.sender, address(this), "LM:UPGRADE", msg.data), "LM:U:INVALID_SCHED_CALL");
globals_.unscheduleCall(msg.sender, "LM:UPGRADE", msg.data);
} else {
require(msg.sender == globals_.securityAdmin(), "LM:U:NO_AUTH");
}
emit Upgraded(version_, arguments_);
IMapleProxyFactory(_factory()).upgradeInstance(version_, arguments_);
}
/**************************************************************************************************************************************/
/*** Loan Funding and Refinancing Functions ***/
/**************************************************************************************************************************************/
function fund(address loan_) external override whenNotPaused nonReentrant onlyPoolDelegate {
address factory_ = ILoanLike(loan_).factory();
IGlobalsLike globals_ = IGlobalsLike(_globals());
require(globals_.isInstanceOf("OT_LOAN_FACTORY", factory_), "LM:F:INVALID_LOAN_FACTORY");
require(ILoanFactoryLike(factory_).isLoan(loan_), "LM:F:INVALID_LOAN_INSTANCE");
require(globals_.isBorrower(ILoanLike(loan_).borrower()), "LM:F:INVALID_BORROWER");
uint256 principal_ = ILoanLike(loan_).principal();
require(principal_ != 0, "LM:F:LOAN_NOT_ACTIVE");
_prepareFundsForLoan(loan_, principal_);
( uint256 fundsLent_, , ) = ILoanLike(loan_).fund();
require(fundsLent_ == principal_, "LM:F:FUNDING_MISMATCH");
_updatePrincipalOut(_int256(fundsLent_));
Payment memory payment_ = _addPayment(loan_);
_updateInterestAccounting(0, _int256(payment_.issuanceRate));
}
function proposeNewTerms(address loan_, address refinancer_, uint256 deadline_, bytes[] calldata calls_)
external override whenNotPaused onlyPoolDelegate isLoan(loan_)
{
ILoanLike(loan_).proposeNewTerms(refinancer_, deadline_, calls_);
}
function rejectNewTerms(address loan_, address refinancer_, uint256 deadline_, bytes[] calldata calls_)
external override whenNotPaused onlyPoolDelegate isLoan(loan_)
{
ILoanLike(loan_).rejectNewTerms(refinancer_, deadline_, calls_);
}
/**************************************************************************************************************************************/
/*** Loan Payment Claim Function ***/
/**************************************************************************************************************************************/
function claim(
int256 principal_,
uint256 interest_,
uint256 delegateServiceFee_,
uint256 platformServiceFee_,
uint40 nextPaymentDueDate_
)
external override whenNotPaused isLoan(msg.sender) nonReentrant
{
uint256 principalRemaining_ = ILoanLike(msg.sender).principal();
// Either a next payment and remaining principal exists, or neither exist and principal is returned.
require(
(nextPaymentDueDate_ > 0 && principalRemaining_ > 0) || // First given it's most likely.
((nextPaymentDueDate_ == 0) && (principalRemaining_ == 0) && (principal_ > 0)),
"LM:C:INVALID"
);
// Calculate the original principal to correctly account for removing `unrealizedLosses` when removing the impairment.
uint256 originalPrincipal_ = uint256(_int256(principalRemaining_) + principal_);
_accountForLoanImpairmentRemoval(msg.sender, originalPrincipal_);
// Transfer the funds from the loan to the `pool`, `poolDelegate`, and `mapleTreasury`.
_distributeClaimedFunds(msg.sender, principal_, interest_, delegateServiceFee_, platformServiceFee_);
// If principal is changing, update `principalOut`.
// If principal is positive, it is being repaid, so `principalOut` is decremented.
// If principal is negative, it is being taken from the Pool, so `principalOut` is incremented.
if (principal_ != 0) {
_updatePrincipalOut(-principal_);
}
// Remove the payment and cache the struct.
Payment memory claimedPayment_ = _removePayment(msg.sender);
int256 accountedInterestAdjustment_
= -_int256(_getIssuance(claimedPayment_.issuanceRate, block.timestamp - claimedPayment_.startDate));
// If no new payment to track, update accounting and account for discrepancies in paid interest vs accrued interest since the
// payment's start date, and exit.
if (nextPaymentDueDate_ == 0) {
return _updateInterestAccounting(accountedInterestAdjustment_, -_int256(claimedPayment_.issuanceRate));
}
if (principal_ < 0) {
address borrower_ = ILoanLike(msg.sender).borrower();
require(IGlobalsLike(_globals()).isBorrower(borrower_), "LM:C:INVALID_BORROWER");
_prepareFundsForLoan(msg.sender, _uint256(-principal_));
}
// Track the new payment.
Payment memory nextPayment_ = _addPayment(msg.sender);
// Update accounting and account for discrepancies in paid interest vs accrued interest since the payment's start date, and exit.
_updateInterestAccounting(accountedInterestAdjustment_, _int256(nextPayment_.issuanceRate) - _int256(claimedPayment_.issuanceRate));
}
/**************************************************************************************************************************************/
/*** Loan Call Functions ***/
/**************************************************************************************************************************************/
function callPrincipal(address loan_, uint256 principal_) external override whenNotPaused onlyPoolDelegate isLoan(loan_) {
ILoanLike(loan_).callPrincipal(principal_);
}
function removeCall(address loan_) external override whenNotPaused onlyPoolDelegate isLoan(loan_) {
ILoanLike(loan_).removeCall();
}
/**************************************************************************************************************************************/
/*** Loan Impairment Functions ***/
/**************************************************************************************************************************************/
function impairLoan(address loan_) external override whenNotPaused isLoan(loan_) {
bool isGovernor_ = msg.sender == _governor();
require(isGovernor_ || msg.sender == _poolDelegate(), "LM:IL:NO_AUTH");
ILoanLike(loan_).impair();
if (isGovernor_) {
_accountForLoanImpairmentAsGovernor(loan_);
} else {
_accountForLoanImpairment(loan_);
}
}
function removeLoanImpairment(address loan_) external override whenNotPaused isLoan(loan_) {
( , bool impairedByGovernor_ ) = _accountForLoanImpairmentRemoval(loan_, ILoanLike(loan_).principal());
require(msg.sender == _governor() || (!impairedByGovernor_ && msg.sender == _poolDelegate()), "LM:RLI:NO_AUTH");
ILoanLike(loan_).removeImpairment();
}
/**************************************************************************************************************************************/
/*** Loan Default Functions ***/
/**************************************************************************************************************************************/
function triggerDefault(address loan_, address liquidatorFactory_)
external override returns (bool liquidationComplete_, uint256 remainingLosses_, uint256 unrecoveredPlatformFees_)
{
liquidatorFactory_; // Silence compiler warning.
( remainingLosses_, unrecoveredPlatformFees_ ) = triggerDefault(loan_);
liquidationComplete_ = true;
}
function triggerDefault(address loan_)
public override whenNotPaused isLoan(loan_) returns (uint256 remainingLosses_, uint256 unrecoveredPlatformFees_)
{
require(msg.sender == poolManager, "LM:TD:NOT_PM");
// Note: Always impair before proceeding, this ensures a consistent approach to reduce the `accountedInterest` for the Loan.
// If the Loan is already impaired, this will be a no-op and just return the `impairedDate`.
// If the Loan is not impaired, the accountedInterest will be updated to block.timestamp,
// which will include the total interest due for the Loan.
uint40 impairedDate_ = _accountForLoanImpairment(loan_);
( , uint256 interest_, uint256 lateInterest_, , uint256 platformServiceFee_ ) = ILoanLike(loan_).getPaymentBreakdown(impairedDate_);
uint256 principal_ = ILoanLike(loan_).principal();
interest_ += lateInterest_;
// Pull any `fundsAsset` in loan into LM.
uint256 recoveredFunds_ = ILoanLike(loan_).repossess(address(this));
// Distribute the recovered funds (to treasury, pool, and borrower) and determine the losses, if any, that must still be realized.
(
remainingLosses_,
unrecoveredPlatformFees_
) = _distributeLiquidationFunds(loan_, principal_, interest_, platformServiceFee_, recoveredFunds_);
// Remove the payment and cache the struct.
Payment memory payment_ = _removePayment(loan_);
// NOTE: This is the amount of interest accounted for, before the loan's impairment,
// that is still in the aggregate `accountedInterest` and offset in `unrealizedLosses`
// The original `impairedDate` is always used over the current `impairedDate` on the Loan,
// this ensures the interest calculated for `unrealizedLosses` matches the original impairment calculation.
uint256 accountedImpairedInterest_ = _getIssuance(payment_.issuanceRate, impairedDate_ - payment_.startDate);
// The payment's interest until the `impairedDate` must be deducted from `accountedInterest`, thus realizing the interest loss.
// The unrealized losses incurred due to the impairment must be deducted from the global `unrealizedLosses`.
// The loan's principal must be deducted from `principalOut`, thus realizing the principal loss.
_updateInterestAccounting(-_int256(accountedImpairedInterest_), 0);
_updateUnrealizedLosses(-_int256(principal_ + accountedImpairedInterest_));
_updatePrincipalOut(-_int256(principal_));
delete impairmentFor[loan_];
}
/**************************************************************************************************************************************/
/*** Internal Functions ***/
/**************************************************************************************************************************************/
function _addPayment(address loan_) internal returns (Payment memory payment_) {
uint256 platformManagementFeeRate_ = IGlobalsLike(_globals()).platformManagementFeeRate(poolManager);
uint256 delegateManagementFeeRate_ = IPoolManagerLike(poolManager).delegateManagementFeeRate();
uint256 managementFeeRate_ = platformManagementFeeRate_ + delegateManagementFeeRate_;
// NOTE: If combined fee is greater than 100%, then cap delegate fee and clamp management fee.
if (managementFeeRate_ > HUNDRED_PERCENT) {
delegateManagementFeeRate_ = HUNDRED_PERCENT - platformManagementFeeRate_;
managementFeeRate_ = HUNDRED_PERCENT;
}
uint256 paymentDueDate_ = ILoanLike(loan_).paymentDueDate();
uint256 dueInterest_ = _getNetInterest(loan_, paymentDueDate_, managementFeeRate_);
// NOTE: Can assume `paymentDueDate_ > block.timestamp` and interest at `block.timestamp` is 0 because payments are only added when
// - loans are funded, or
// - payments are claimed, resulting in a new payment.
uint256 paymentIssuanceRate_ = (dueInterest_ * PRECISION) / (paymentDueDate_ - block.timestamp);
paymentFor[loan_] = payment_ = Payment({
platformManagementFeeRate: _uint24(platformManagementFeeRate_),
delegateManagementFeeRate: _uint24(delegateManagementFeeRate_),
startDate: _uint40(block.timestamp),
issuanceRate: _uint168(paymentIssuanceRate_)
});
emit PaymentAdded(
loan_,
platformManagementFeeRate_,
delegateManagementFeeRate_,
paymentDueDate_,
paymentIssuanceRate_
);
}
function _accountForLoanImpairment(address loan_, bool isGovernor_) internal returns (uint40 impairedDate_) {
impairedDate_ = impairmentFor[loan_].impairedDate;
// NOTE: Impairing an already-impaired loan simply updates the `dateImpaired` of the loan, which can push the due date further,
// however, the `impairedDate` in the struct should not be updated since it defines the moment when accounting for the loan's
// payment was paused, and is needed to restore accounting for the eventual removal of the impairment, or the default.
if (impairedDate_ != 0) return impairedDate_;
Payment memory payment_ = paymentFor[loan_];
impairmentFor[loan_] = Impairment(impairedDate_ = _uint40(block.timestamp), isGovernor_);
// Account for all interest until now (including this payment's), then remove payment's `issuanceRate` from global `issuanceRate`.
_updateInterestAccounting(0, -_int256(payment_.issuanceRate));
uint256 principal_ = ILoanLike(loan_).principal();
// Add the payment's entire interest until now (negating above), and the loan's principal, to unrealized losses.
_updateUnrealizedLosses(_int256(principal_ + _getIssuance(payment_.issuanceRate, block.timestamp - payment_.startDate)));
}
function _accountForLoanImpairment(address loan_) internal returns (uint40 impairedDate_) {
impairedDate_ = _accountForLoanImpairment(loan_, false);
}
function _accountForLoanImpairmentAsGovernor(address loan_) internal returns (uint40 impairedDate_) {
impairedDate_ = _accountForLoanImpairment(loan_, true);
}
function _accountForLoanImpairmentRemoval(address loan_, uint256 originalPrincipal_) internal returns (uint40 impairedDate_, bool impairedByGovernor_) {
Impairment memory impairment_ = impairmentFor[loan_];
impairedDate_ = impairment_.impairedDate;
impairedByGovernor_ = impairment_.impairedByGovernor;
if (impairedDate_ == 0) return ( impairedDate_, impairedByGovernor_ );
delete impairmentFor[loan_];
Payment memory payment_ = paymentFor[loan_];
// Subtract the payment's entire interest until it's impairment date, and the loan's principal, from unrealized losses.
_updateUnrealizedLosses(-_int256(originalPrincipal_ + _getIssuance(payment_.issuanceRate, impairedDate_ - payment_.startDate)));
// Account for all interest until now, adjusting for payment's interest between its impairment date and now,
// then add payment's `issuanceRate` to the global `issuanceRate`.
// NOTE: Upon impairment, for payment's interest between its start date and its impairment date were accounted for.
_updateInterestAccounting(
_int256(_getIssuance(payment_.issuanceRate, block.timestamp - impairedDate_)),
_int256(payment_.issuanceRate)
);
}
function _removePayment(address loan_) internal returns (Payment memory payment_) {
payment_ = paymentFor[loan_];
delete paymentFor[loan_];
emit PaymentRemoved(loan_);
}
function _updateInterestAccounting(int256 accountedInterestAdjustment_, int256 issuanceRateAdjustment_) internal {
// NOTE: Order of operations is important as `accruedInterest()` depends on the pre-adjusted `issuanceRate` and `domainStart`.
accountedInterest = _uint112(_max(_int256(accountedInterest + accruedInterest()) + accountedInterestAdjustment_, 0));
domainStart = _uint40(block.timestamp);
issuanceRate = _uint256(_max(_int256(issuanceRate) + issuanceRateAdjustment_, 0));
emit AccountingStateUpdated(issuanceRate, accountedInterest);
}
function _updatePrincipalOut(int256 principalOutAdjustment_) internal {
emit PrincipalOutUpdated(principalOut = _uint128(_max(_int256(principalOut) + principalOutAdjustment_, 0)));
}
function _updateUnrealizedLosses(int256 lossesAdjustment_) internal {
emit UnrealizedLossesUpdated(unrealizedLosses = _uint128(_max(_int256(unrealizedLosses) + lossesAdjustment_, 0)));
}
/**************************************************************************************************************************************/
/*** Funds Distribution Functions ***/
/**************************************************************************************************************************************/
function _distributeClaimedFunds(
address loan_,
int256 principal_,
uint256 interest_,
uint256 delegateServiceFee_,
uint256 platformServiceFee_
)
internal
{
Payment memory payment_ = paymentFor[loan_];
uint256 delegateManagementFee_ = _getRatedAmount(interest_, payment_.delegateManagementFeeRate);
uint256 platformManagementFee_ = _getRatedAmount(interest_, payment_.platformManagementFeeRate);
// If the coverage is not sufficient move the delegate service fee to the platform and remove the delegate management fee.
if (!IPoolManagerLike(poolManager).hasSufficientCover()) {
platformServiceFee_ += delegateServiceFee_;
delegateServiceFee_ = 0;
delegateManagementFee_ = 0;
}
uint256 netInterest_ = interest_ - (platformManagementFee_ + delegateManagementFee_);
principal_ = principal_ > int256(0) ? principal_ : int256(0);
emit ClaimedFundsDistributed(
loan_,
uint256(principal_),
interest_,
delegateManagementFee_,
delegateServiceFee_,
platformManagementFee_,
platformServiceFee_
);
address fundsAsset_ = fundsAsset;
require(_transfer(fundsAsset_, _pool(), uint256(principal_) + netInterest_), "LM:DCF:TRANSFER_P");
require(_transfer(fundsAsset_, _poolDelegate(), delegateServiceFee_ + delegateManagementFee_), "LM:DCF:TRANSFER_PD");
require(_transfer(fundsAsset_, _treasury(), platformServiceFee_ + platformManagementFee_), "LM:DCF:TRANSFER_MT");
}
function _distributeLiquidationFunds(
address loan_,
uint256 principal_,
uint256 interest_,
uint256 platformServiceFee_,
uint256 recoveredFunds_
)
internal returns (uint256 remainingLosses_, uint256 unrecoveredPlatformFees_)
{
Payment memory payment_ = paymentFor[loan_];
uint256 platformManagementFee_ = _getRatedAmount(interest_, payment_.platformManagementFeeRate);
uint256 delegateManagementFee_ = _getRatedAmount(interest_, payment_.delegateManagementFeeRate);
uint256 netInterest_ = interest_ - (platformManagementFee_ + delegateManagementFee_);
uint256 platformFee_ = platformServiceFee_ + platformManagementFee_;
uint256 toTreasury_ = _min(recoveredFunds_, platformFee_);
unrecoveredPlatformFees_ = platformFee_ - toTreasury_;
recoveredFunds_ -= toTreasury_;
uint256 toPool_ = _min(recoveredFunds_, principal_ + netInterest_);
remainingLosses_ = principal_ + netInterest_ - toPool_;
recoveredFunds_ -= toPool_;
emit ExpectedClaim(loan_, principal_, netInterest_, platformManagementFee_, platformServiceFee_);
emit LiquidatedFundsDistributed(loan_, recoveredFunds_, toPool_, toTreasury_);
// NOTE: Cannot cache `fundsAsset` due to "Stack too deep" issue.
require(_transfer(fundsAsset, ILoanLike(loan_).borrower(), recoveredFunds_), "LM:DLF:TRANSFER_B");
require(_transfer(fundsAsset, _pool(), toPool_), "LM:DLF:TRANSFER_P");
require(_transfer(fundsAsset, _treasury(), toTreasury_), "LM:DLF:TRANSFER_MT");
}
function _prepareFundsForLoan(address loan_, uint256 amount_) internal {
// Request funds from pool manager.
IPoolManagerLike(poolManager).requestFunds(address(this), amount_);
// Approve the loan to use these funds.
require(ERC20Helper.approve(fundsAsset, loan_, amount_), "LM:PFFL:APPROVE_FAILED");
}
function _transfer(address asset_, address to_, uint256 amount_) internal returns (bool success_) {
success_ = (to_ != address(0)) && ((amount_ == 0) || ERC20Helper.transfer(asset_, to_, amount_));
}
/**************************************************************************************************************************************/
/*** Internal Loan Accounting Helper Functions ***/
/**************************************************************************************************************************************/
function _getIssuance(uint256 issuanceRate_, uint256 interval_) internal pure returns (uint256 issuance_) {
issuance_ = (issuanceRate_ * interval_) / PRECISION;
}
function _getNetInterest(address loan_, uint256 timestamp_, uint256 managementFeeRate_) internal view returns (uint256 netInterest_) {
( , uint256 interest_, , , ) = ILoanLike(loan_).getPaymentBreakdown(timestamp_);
netInterest_ = _getNetInterest(interest_, managementFeeRate_);
}
function _getNetInterest(uint256 interest_, uint256 feeRate_) internal pure returns (uint256 netInterest_) {
// NOTE: This ensures that `netInterest_ == interest_ - fee_`, since absolutes are subtracted, not rates.
netInterest_ = interest_ - _getRatedAmount(interest_, feeRate_);
}
function _getRatedAmount(uint256 amount_, uint256 rate_) internal pure returns (uint256 ratedAmount_) {
ratedAmount_ = (amount_ * rate_) / HUNDRED_PERCENT;
}
/**************************************************************************************************************************************/
/*** Loan Manager View Functions ***/
/**************************************************************************************************************************************/
function accruedInterest() public view override returns (uint256 accruedInterest_) {
uint256 issuanceRate_ = issuanceRate;
accruedInterest_ = issuanceRate_ == 0 ? 0 : _getIssuance(issuanceRate_, block.timestamp - domainStart);
}
function assetsUnderManagement() public view virtual override returns (uint256 assetsUnderManagement_) {
assetsUnderManagement_ = principalOut + accountedInterest + accruedInterest();
}
/**************************************************************************************************************************************/
/*** Protocol Address View Functions ***/
/**************************************************************************************************************************************/
function factory() external view override returns (address factory_) {
factory_ = _factory();
}
function implementation() external view override returns (address implementation_) {
implementation_ = _implementation();
}
/**************************************************************************************************************************************/
/*** Internal View Functions ***/
/**************************************************************************************************************************************/
function _globals() internal view returns (address globals_) {
globals_ = IMapleProxyFactory(_factory()).mapleGlobals();
}
function _governor() internal view returns (address governor_) {
governor_ = IGlobalsLike(_globals()).governor();
}
function _pool() internal view returns (address pool_) {
pool_ = IPoolManagerLike(poolManager).pool();
}
function _poolDelegate() internal view returns (address poolDelegate_) {
poolDelegate_ = IPoolManagerLike(poolManager).poolDelegate();
}
function _revertIfNotLoan(address loan_) internal view {
require(paymentFor[loan_].startDate != 0, "LM:NOT_LOAN");
}
function _revertIfNotPoolDelegate() internal view {
require(msg.sender == _poolDelegate(), "LM:NOT_PD");
}
function _revertIfPaused() internal view {
require(!IGlobalsLike(_globals()).isFunctionPaused(msg.sig), "LM:PAUSED");
}
function _treasury() internal view returns (address treasury_) {
treasury_ = IGlobalsLike(_globals()).mapleTreasury();
}
/**************************************************************************************************************************************/
/*** Internal Pure Utility Functions ***/
/**************************************************************************************************************************************/
function _int256(uint256 input_) internal pure returns (int256 output_) {
require(input_ <= uint256(type(int256).max), "LM:UINT256_OOB_FOR_INT256");
output_ = int256(input_);
}
function _max(int256 a_, int256 b_) internal pure returns (int256 maximum_) {
maximum_ = a_ > b_ ? a_ : b_;
}
function _min(uint256 a_, uint256 b_) internal pure returns (uint256 minimum_) {
minimum_ = a_ < b_ ? a_ : b_;
}
function _uint24(uint256 input_) internal pure returns (uint24 output_) {
require(input_ <= type(uint24).max, "LM:UINT256_OOB_FOR_UINT24");
output_ = uint24(input_);
}
function _uint40(uint256 input_) internal pure returns (uint40 output_) {
require(input_ <= type(uint40).max, "LM:UINT256_OOB_FOR_UINT40");
output_ = uint40(input_);
}
function _uint112(int256 input_) internal pure returns (uint112 output_) {
require(input_ <= int256(uint256(type(uint112).max)) && input_ >= 0, "LM:INT256_OOB_FOR_UINT112");
output_ = uint112(uint256(input_));
}
function _uint128(int256 input_) internal pure returns (uint128 output_) {
require(input_ <= int256(uint256(type(uint128).max)) && input_ >= 0, "LM:INT256_OOB_FOR_UINT128");
output_ = uint128(uint256(input_));
}
function _uint168(uint256 input_) internal pure returns (uint168 output_) {
require(input_ <= type(uint168).max, "LM:UINT256_OOB_FOR_UINT168");
output_ = uint168(input_);
}
function _uint168(int256 input_) internal pure returns (uint168 output_) {
require(input_ <= int256(uint256(type(uint168).max)) && input_ >= 0, "LM:INT256_OOB_FOR_UINT168");
output_ = uint168(uint256(input_));
}
function _uint256(int256 input_) internal pure returns (uint256 output_) {
require(input_ >= 0, "LM:INT256_OOB_FOR_UINT256");
output_ = uint256(input_);
}
}
LoanManagerStorage.sol 36 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.7;
import { ILoanManagerStorage } from "./interfaces/ILoanManagerStorage.sol";
abstract contract LoanManagerStorage is ILoanManagerStorage {
struct Impairment {
uint40 impairedDate; // Slot 1: uint40 - Until year 36,812.
bool impairedByGovernor; // bool
}
struct Payment {
uint24 platformManagementFeeRate; // Slot 1: uint24 - max = 1.6e7 (1600%)
uint24 delegateManagementFeeRate; // uint24 - max = 1.6e7 (1600%)
uint40 startDate; // uint40 - Until year 36,812.
uint168 issuanceRate; // uint168 - max = 3.7e50 (3.2e10 * 1e18 / day)
}
uint256 internal _locked; // Used when checking for reentrancy.
uint40 public override domainStart; // Slot 1: uint40 - Until year 36,812.
uint112 public override accountedInterest; // uint112 - max = 5.1e33
uint128 public override principalOut; // Slot 2: uint128 - max = 3.4e38
uint128 public override unrealizedLosses; // uint128 - max = 3.4e38
uint256 public override issuanceRate; // Slot 3: uint256 - max = 1.1e77
// NOTE: Addresses below uints to preserve full storage slots
address public override fundsAsset;
address public override poolManager;
mapping(address => Impairment) public override impairmentFor;
mapping(address => Payment) public override paymentFor;
}
Interfaces.sol 105 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.7;
interface IGlobalsLike {
function canDeploy(address caller_) external view returns (bool canDeploy_);
function governor() external view returns (address governor_);
function isBorrower(address borrower_) external view returns (bool isBorrower_);
function isFunctionPaused(bytes4 sig_) external view returns (bool isFunctionPaused_);
function isInstanceOf(bytes32 instanceId, address instance_) external view returns (bool isInstance_);
function isValidScheduledCall(address caller_, address contract_, bytes32 functionId_, bytes calldata callData_)
external view returns (bool isValid_);
function mapleTreasury() external view returns (address mapleTreasury_);
function platformManagementFeeRate(address poolManager_) external view returns (uint256 platformManagementFeeRate_);
function securityAdmin() external view returns (address securityAdmin_);
function unscheduleCall(address caller_, bytes32 functionId_, bytes calldata callData_) external;
}
interface IMapleProxyFactoryLike {
function isInstance(address instance_) external returns (bool isInstance_);
function mapleGlobals() external returns (address globals_);
}
interface ILoanFactoryLike {
function isLoan(address loan_) external view returns (bool isLoan_);
}
interface ILoanLike {
function borrower() external view returns (address borrower_);
function callPrincipal(uint256 principalToReturn_) external returns (uint40 paymentDueDate_, uint40 defaultDate_);
function factory() external view returns (address factory_);
function fund() external returns (uint256 fundsLent_, uint40 paymentDueDate_, uint40 defaultDate_);
function impair() external returns (uint40 paymentDueDate_, uint40 defaultDate_);
function paymentDueDate() external view returns (uint40 paymentDueDate_);
function getPaymentBreakdown(uint256 paymentTimestamp_)
external view
returns (
uint256 principal_,
uint256 interest_,
uint256 lateInterest_,
uint256 delegateServiceFee_,
uint256 platformServiceFee_
);
function principal() external view returns (uint256 principal_);
function proposeNewTerms(
address refinancer_,
uint256 deadline_,
bytes[] calldata calls_
) external returns (bytes32 refinanceCommitment_);
function rejectNewTerms(
address refinancer_,
uint256 deadline_,
bytes[] calldata calls_
) external returns (bytes32 refinanceCommitment_);
function removeCall() external returns (uint40 paymentDueDate_, uint40 defaultDate_);
function removeImpairment() external returns (uint40 paymentDueDate_, uint40 defaultDate_);
function repossess(address destination_) external returns (uint256 fundsRepossessed_);
}
interface IPoolManagerLike {
function asset() external view returns (address asset_);
function delegateManagementFeeRate() external view returns (uint256 delegateManagementFeeRate_);
function factory() external view returns (address factory_);
function hasSufficientCover() external view returns (bool hasSufficientCover_);
function pool() external view returns (address pool_);
function poolDelegate() external view returns (address poolDelegate_);
function requestFunds(address destination_, uint256 principal_) external;
}
ILoanManager.sol 223 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.7;
import { IMapleProxied } from "../../modules/maple-proxy-factory/contracts/interfaces/IMapleProxied.sol";
import { ILoanManagerStorage } from "./ILoanManagerStorage.sol";
interface ILoanManager is IMapleProxied, ILoanManagerStorage {
/**************************************************************************************************************************************/
/*** Events ***/
/**************************************************************************************************************************************/
/**
* @dev Emitted when the accounting state of the loan manager is updated.
* @param issuanceRate_ New value for the issuance rate.
* @param accountedInterest_ The amount of accounted interest.
*/
event AccountingStateUpdated(uint256 issuanceRate_, uint112 accountedInterest_);
/**
* @dev Funds have been claimed and distributed to the Pool, Pool Delegate, and Maple Treasury.
* @param loan_ The address of the loan contract.
* @param principal_ The amount of principal paid.
* @param netInterest_ The amount of net interest paid.
* @param delegateManagementFee_ The amount of delegate management fees paid.
* @param delegateServiceFee_ The amount of delegate service fees paid.
* @param platformManagementFee_ The amount of platform management fees paid.
* @param platformServiceFee_ The amount of platform service fees paid.
*/
event ClaimedFundsDistributed(
address indexed loan_,
uint256 principal_,
uint256 netInterest_,
uint256 delegateManagementFee_,
uint256 delegateServiceFee_,
uint256 platformManagementFee_,
uint256 platformServiceFee_
);
/**
* @dev Funds that were expected to be claimed and distributed to the Pool and Maple Treasury.
* @param loan_ The address of the loan contract.
* @param principal_ The amount of principal that was expected to be paid.
* @param netInterest_ The amount of net interest that was expected to be paid.
* @param platformManagementFee_ The amount of platform management fees that were expected to be paid.
* @param platformServiceFee_ The amount of platform service fees that were expected to paid.
*/
event ExpectedClaim(
address indexed loan_,
uint256 principal_,
uint256 netInterest_,
uint256 platformManagementFee_,
uint256 platformServiceFee_
);
/**
* @dev Funds that were liquidated and distributed to the Pool, Maple Treasury, and Borrower.
* @param loan_ The address of the loan contract that defaulted and was liquidated.
* @param toBorrower_ The amount of recovered funds transferred to the Borrower.
* @param toPool_ The amount of recovered funds transferred to the Pool.
* @param toTreasury_ The amount of recovered funds transferred to the Treasury.
*/
event LiquidatedFundsDistributed(address indexed loan_, uint256 toBorrower_, uint256 toPool_, uint256 toTreasury_);
/**
* @dev Emitted when a payment is added to the LoanManager payments mapping.
* @param loan_ The address of the loan.
* @param platformManagementFeeRate_ The amount of platform management rate that will be used for the payment distribution.
* @param delegateManagementFeeRate_ The amount of delegate management rate that will be used for the payment distribution.
* @param paymentDueDate_ The due date of the payment.
* @param issuanceRate_ The issuance of the payment, 1e27 precision.
*/
event PaymentAdded(
address indexed loan_,
uint256 platformManagementFeeRate_,
uint256 delegateManagementFeeRate_,
uint256 paymentDueDate_,
uint256 issuanceRate_
);
/**
* @dev Emitted when a payment is removed from the LoanManager payments mapping.
* @param loan_ The address of the loan.
*/
event PaymentRemoved(address indexed loan_);
/**
* @dev Emitted when principal out is updated
* @param principalOut_ The new value for principal out.
*/
event PrincipalOutUpdated(uint128 principalOut_);
/**
* @dev Emitted when unrealized losses is updated.
* @param unrealizedLosses_ The new value for unrealized losses.
*/
event UnrealizedLossesUpdated(uint128 unrealizedLosses_);
/**************************************************************************************************************************************/
/*** External Functions ***/
/**************************************************************************************************************************************/
// NOTE: setPendingLender and acceptPendingLender were not implemented in the LoanManager even though they exist on the Loan
// contract. This is because the Loan will support this functionality always, but it was not deemed necessary for the
// LoanManager to support this functionality.
/**
* @dev Calls a loan.
* @param loan_ Loan to be called.
* @param principal_ Amount of principal to call the Loan with.
*/
function callPrincipal(address loan_, uint256 principal_) external;
/**
* @dev Called by loans when payments are made, updating the accounting.
* @param principal_ The difference in principal. Positive if net principal change moves funds into pool, negative if it moves
* funds out of pool.
* @param interest_ The amount of interest paid.
* @param platformServiceFee_ The amount of platform service fee paid.
* @param delegateServiceFee_ The amount of delegate service fee paid.
* @param paymentDueDate_ The new payment due date.
*/
function claim(
int256 principal_,
uint256 interest_,
uint256 delegateServiceFee_,
uint256 platformServiceFee_,
uint40 paymentDueDate_
) external;
/**
* @dev Funds a new loan.
* @param loan_ Loan to be funded.
*/
function fund(address loan_) external;
/**
* @dev Triggers the impairment of a loan.
* @param loan_ Loan to trigger the loan impairment.
*/
function impairLoan(address loan_) external;
/**
* @dev Proposes new terms for a loan.
* @param loan_ The loan to propose new changes to.
* @param refinancer_ The refinancer to use in the refinance.
* @param deadline_ The deadline by which the borrower must accept the new terms.
* @param calls_ The array of calls to be made to the refinancer.
*/
function proposeNewTerms(address loan_, address refinancer_, uint256 deadline_, bytes[] calldata calls_) external;
/**
* @dev Reject/cancel proposed new terms for a loan.
* @param loan_ The loan with the proposed new changes.
* @param refinancer_ The refinancer to use in the refinance.
* @param deadline_ The deadline by which the borrower must accept the new terms.
* @param calls_ The array of calls to be made to the refinancer.
*/
function rejectNewTerms(address loan_, address refinancer_, uint256 deadline_, bytes[] calldata calls_) external;
/**
* @dev Removes a loan call.
* @param loan_ Loan to remove call for.
*/
function removeCall(address loan_) external;
/**
* @dev Removes the loan impairment for a loan.
* @param loan_ Loan to remove the loan impairment.
*/
function removeLoanImpairment(address loan_) external;
/**
* @dev Triggers the default of a loan. Different interface for PM to accommodate vs FT-LM.
* @param loan_ Loan to trigger the default.
* @param liquidatorFactory_ Address of the liquidator factory (ignored for open-term loans).
* @return liquidationComplete_ If the liquidation is complete (always true for open-term loans)
* @return remainingLosses_ The amount of un-recovered principal and interest (net of management fees).
* @return unrecoveredPlatformFees_ The amount of un-recovered platform fees.
*/
function triggerDefault(
address loan_,
address liquidatorFactory_
) external returns (bool liquidationComplete_, uint256 remainingLosses_, uint256 unrecoveredPlatformFees_);
/**
* @dev Triggers the default of a loan.
* @param loan_ Loan to trigger the default.
* @return remainingLosses_ The amount of un-recovered principal and interest (net of management fees).
* @return unrecoveredPlatformFees_ The amount of un-recovered platform fees.
*/
function triggerDefault(address loan_) external returns (uint256 remainingLosses_, uint256 unrecoveredPlatformFees_);
/**************************************************************************************************************************************/
/*** View Functions ***/
/**************************************************************************************************************************************/
/**
* @dev Returns the value considered as the hundred percent.
* @return hundredPercent_ The value considered as the hundred percent.
*/
function HUNDRED_PERCENT() external returns (uint256 hundredPercent_);
/**
* @dev Returns the precision used for the contract.
* @return precision_ The precision used for the contract.
*/
function PRECISION() external returns (uint256 precision_);
/**
* @dev Gets the amount of accrued interest up until this point in time.
* @return accruedInterest_ The amount of accrued interest up until this point in time.
*/
function accruedInterest() external view returns (uint256 accruedInterest_);
/**
* @dev Gets the amount of assets under the management of the contract.
* @return assetsUnderManagement_ The amount of assets under the management of the contract.
*/
function assetsUnderManagement() external view returns (uint256 assetsUnderManagement_);
}
ERC20Helper.sol 43 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;
import { IERC20Like } from "./interfaces/IERC20Like.sol";
/**
* @title Small Library to standardize erc20 token interactions.
*/
library ERC20Helper {
/**************************************************************************************************************************************/
/*** Internal Functions ***/
/**************************************************************************************************************************************/
function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) {
return _call(token_, abi.encodeWithSelector(IERC20Like.transfer.selector, to_, amount_));
}
function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) {
return _call(token_, abi.encodeWithSelector(IERC20Like.transferFrom.selector, from_, to_, amount_));
}
function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) {
// If setting approval to zero fails, return false.
if (!_call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, uint256(0)))) return false;
// If `amount_` is zero, return true as the previous step already did this.
if (amount_ == uint256(0)) return true;
// Return the result of setting the approval to `amount_`.
return _call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, amount_));
}
function _call(address token_, bytes memory data_) private returns (bool success_) {
if (token_.code.length == uint256(0)) return false;
bytes memory returnData;
( success_, returnData ) = token_.call(data_);
return success_ && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
}
}
ILoanManagerStorage.sol 71 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.7;
interface ILoanManagerStorage {
/**
* @dev Gets the amount of accounted interest.
* @return accountedInterest_ The amount of accounted interest.
*/
function accountedInterest() external view returns (uint112 accountedInterest_);
/**
* @dev Gets the timestamp of the domain start.
* @return domainStart_ The timestamp of the domain start.
*/
function domainStart() external view returns (uint40 domainStart_);
/**
* @dev Gets the address of the funds asset.
* @return fundsAsset_ The address of the funds asset.
*/
function fundsAsset() external view returns (address fundsAsset_);
/**
* @dev Gets the information for an impairment.
* @param loan_ The address of the loan.
* @return impairedDate The date the impairment was triggered.
* @return impairedByGovernor True if the impairment was triggered by the governor.
*/
function impairmentFor(address loan_) external view returns (uint40 impairedDate, bool impairedByGovernor);
/**
* @dev Gets the current issuance rate.
* @return issuanceRate_ The value for the issuance rate.
*/
function issuanceRate() external view returns (uint256 issuanceRate_);
/**
* @dev Gets the information for a payment.
* @param loan_ The address of the loan.
* @return platformManagementFeeRate The value for the platform management fee rate.
* @return delegateManagementFeeRate The value for the delegate management fee rate.
* @return startDate The start date of the payment.
* @return issuanceRate The issuance rate for the loan.
*/
function paymentFor(address loan_) external view returns (
uint24 platformManagementFeeRate,
uint24 delegateManagementFeeRate,
uint40 startDate,
uint168 issuanceRate
);
/**
* @dev Gets the address of the pool manager.
* @return poolManager_ The address of the pool manager.
*/
function poolManager() external view returns (address poolManager_);
/**
* @dev Gets the amount of principal out.
* @return principalOut_ The amount of principal out.
*/
function principalOut() external view returns (uint128 principalOut_);
/**
* @dev Returns the amount unrealized losses.
* @return unrealizedLosses_ Amount of unrealized losses.
*/
function unrealizedLosses() external view returns (uint128 unrealizedLosses_);
}
IERC20Like.sol 13 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;
/// @title Interface of the ERC20 standard as needed by ERC20Helper.
interface IERC20Like {
function approve(address spender_, uint256 amount_) external returns (bool success_);
function transfer(address recipient_, uint256 amount_) external returns (bool success_);
function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
}
MapleProxiedInternals.sol 7 lines
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.7;
import { ProxiedInternals } from "../modules/proxy-factory/contracts/ProxiedInternals.sol";
/// @title A Maple implementation that is to be proxied, will need MapleProxiedInternals.
abstract contract MapleProxiedInternals is ProxiedInternals { }
IMapleProxied.sol 24 lines
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.7;
import { IProxied } from "../../modules/proxy-factory/contracts/interfaces/IProxied.sol";
/// @title A Maple implementation that is to be proxied, must implement IMapleProxied.
interface IMapleProxied is IProxied {
/**
* @dev The instance was upgraded.
* @param toVersion_ The new version of the loan.
* @param arguments_ The upgrade arguments, if any.
*/
event Upgraded(uint256 toVersion_, bytes arguments_);
/**
* @dev Upgrades a contract implementation to a specific version.
* Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled.
* @param toVersion_ The version to upgrade to.
* @param arguments_ Some encoded arguments to use for the upgrade.
*/
function upgrade(uint256 toVersion_, bytes calldata arguments_) external;
}
IMapleProxyFactory.sol 189 lines
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.7;
import { IDefaultImplementationBeacon } from "../../modules/proxy-factory/contracts/interfaces/IDefaultImplementationBeacon.sol";
/// @title A Maple factory for Proxy contracts that proxy MapleProxied implementations.
interface IMapleProxyFactory is IDefaultImplementationBeacon {
/**************************************************************************************************************************************/
/*** Events ***/
/**************************************************************************************************************************************/
/**
* @dev A default version was set.
* @param version_ The default version.
*/
event DefaultVersionSet(uint256 indexed version_);
/**
* @dev A version of an implementation, at some address, was registered, with an optional initializer.
* @param version_ The version registered.
* @param implementationAddress_ The address of the implementation.
* @param initializer_ The address of the initializer, if any.
*/
event ImplementationRegistered(uint256 indexed version_, address indexed implementationAddress_, address indexed initializer_);
/**
* @dev A proxy contract was deployed with some initialization arguments.
* @param version_ The version of the implementation being proxied by the deployed proxy contract.
* @param instance_ The address of the proxy contract deployed.
* @param initializationArguments_ The arguments used to initialize the proxy contract, if any.
*/
event InstanceDeployed(uint256 indexed version_, address indexed instance_, bytes initializationArguments_);
/**
* @dev A instance has upgraded by proxying to a new implementation, with some migration arguments.
* @param instance_ The address of the proxy contract.
* @param fromVersion_ The initial implementation version being proxied.
* @param toVersion_ The new implementation version being proxied.
* @param migrationArguments_ The arguments used to migrate, if any.
*/
event InstanceUpgraded(address indexed instance_, uint256 indexed fromVersion_, uint256 indexed toVersion_, bytes migrationArguments_);
/**
* @dev The MapleGlobals was set.
* @param mapleGlobals_ The address of a Maple Globals contract.
*/
event MapleGlobalsSet(address indexed mapleGlobals_);
/**
* @dev An upgrade path was disabled, with an optional migrator contract.
* @param fromVersion_ The starting version of the upgrade path.
* @param toVersion_ The destination version of the upgrade path.
*/
event UpgradePathDisabled(uint256 indexed fromVersion_, uint256 indexed toVersion_);
/**
* @dev An upgrade path was enabled, with an optional migrator contract.
* @param fromVersion_ The starting version of the upgrade path.
* @param toVersion_ The destination version of the upgrade path.
* @param migrator_ The address of the migrator, if any.
*/
event UpgradePathEnabled(uint256 indexed fromVersion_, uint256 indexed toVersion_, address indexed migrator_);
/**************************************************************************************************************************************/
/*** State Variables ***/
/**************************************************************************************************************************************/
/**
* @dev The default version.
*/
function defaultVersion() external view returns (uint256 defaultVersion_);
/**
* @dev The address of the MapleGlobals contract.
*/
function mapleGlobals() external view returns (address mapleGlobals_);
/**
* @dev Whether the upgrade is enabled for a path from a version to another version.
* @param toVersion_ The initial version.
* @param fromVersion_ The destination version.
* @return allowed_ Whether the upgrade is enabled.
*/
function upgradeEnabledForPath(uint256 toVersion_, uint256 fromVersion_) external view returns (bool allowed_);
/**************************************************************************************************************************************/
/*** State Changing Functions ***/
/**************************************************************************************************************************************/
/**
* @dev Deploys a new instance proxying the default implementation version, with some initialization arguments.
* Uses a nonce and `msg.sender` as a salt for the CREATE2 opcode during instantiation to produce deterministic addresses.
* @param arguments_ The initialization arguments to use for the instance deployment, if any.
* @param salt_ The salt to use in the contract creation process.
* @return instance_ The address of the deployed proxy contract.
*/
function createInstance(bytes calldata arguments_, bytes32 salt_) external returns (address instance_);
/**
* @dev Enables upgrading from a version to a version of an implementation, with an optional migrator.
* Only the Governor can call this function.
* @param fromVersion_ The starting version of the upgrade path.
* @param toVersion_ The destination version of the upgrade path.
* @param migrator_ The address of the migrator, if any.
*/
function enableUpgradePath(uint256 fromVersion_, uint256 toVersion_, address migrator_) external;
/**
* @dev Disables upgrading from a version to a version of a implementation.
* Only the Governor can call this function.
* @param fromVersion_ The starting version of the upgrade path.
* @param toVersion_ The destination version of the upgrade path.
*/
function disableUpgradePath(uint256 fromVersion_, uint256 toVersion_) external;
/**
* @dev Registers the address of an implementation contract as a version, with an optional initializer.
* Only the Governor can call this function.
* @param version_ The version to register.
* @param implementationAddress_ The address of the implementation.
* @param initializer_ The address of the initializer, if any.
*/
function registerImplementation(uint256 version_, address implementationAddress_, address initializer_) external;
/**
* @dev Sets the default version.
* Only the Governor can call this function.
* @param version_ The implementation version to set as the default.
*/
function setDefaultVersion(uint256 version_) external;
/**
* @dev Sets the Maple Globals contract.
* Only the Governor can call this function.
* @param mapleGlobals_ The address of a Maple Globals contract.
*/
function setGlobals(address mapleGlobals_) external;
/**
* @dev Upgrades the calling proxy contract's implementation, with some migration arguments.
* @param toVersion_ The implementation version to upgrade the proxy contract to.
* @param arguments_ The migration arguments, if any.
*/
function upgradeInstance(uint256 toVersion_, bytes calldata arguments_) external;
/**************************************************************************************************************************************/
/*** View Functions ***/
/**************************************************************************************************************************************/
/**
* @dev Returns the deterministic address of a potential proxy, given some arguments and salt.
* @param arguments_ The initialization arguments to be used when deploying the proxy.
* @param salt_ The salt to be used when deploying the proxy.
* @return instanceAddress_ The deterministic address of a potential proxy.
*/
function getInstanceAddress(bytes calldata arguments_, bytes32 salt_) external view returns (address instanceAddress_);
/**
* @dev Returns the address of an implementation version.
* @param version_ The implementation version.
* @return implementation_ The address of the implementation.
*/
function implementationOf(uint256 version_) external view returns (address implementation_);
/**
* @dev Returns if a given address has been deployed by this factory/
* @param instance_ The address to check.
* @return isInstance_ A boolean indication if the address has been deployed by this factory.
*/
function isInstance(address instance_) external view returns (bool isInstance_);
/**
* @dev Returns the address of a migrator contract for a migration path (from version, to version).
* If oldVersion_ == newVersion_, the migrator is an initializer.
* @param oldVersion_ The old version.
* @param newVersion_ The new version.
* @return migrator_ The address of a migrator contract.
*/
function migratorForPath(uint256 oldVersion_, uint256 newVersion_) external view returns (address migrator_);
/**
* @dev Returns the version of an implementation contract.
* @param implementation_ The address of an implementation contract.
* @return version_ The version of the implementation contract.
*/
function versionOf(address implementation_) external view returns (uint256 version_);
}
ProxiedInternals.sol 50 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;
import { SlotManipulatable } from "./SlotManipulatable.sol";
/// @title An implementation that is to be proxied, will need ProxiedInternals.
abstract contract ProxiedInternals is SlotManipulatable {
/// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.factory') - 1`.
bytes32 private constant FACTORY_SLOT = bytes32(0x7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af1);
/// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`.
bytes32 private constant IMPLEMENTATION_SLOT = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
/// @dev Delegatecalls to a migrator contract to manipulate storage during an initialization or migration.
function _migrate(address migrator_, bytes calldata arguments_) internal virtual returns (bool success_) {
uint256 size;
assembly {
size := extcodesize(migrator_)
}
if (size == uint256(0)) return false;
( success_, ) = migrator_.delegatecall(arguments_);
}
/// @dev Sets the factory address in storage.
function _setFactory(address factory_) internal virtual returns (bool success_) {
_setSlotValue(FACTORY_SLOT, bytes32(uint256(uint160(factory_))));
return true;
}
/// @dev Sets the implementation address in storage.
function _setImplementation(address implementation_) internal virtual returns (bool success_) {
_setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(implementation_))));
return true;
}
/// @dev Returns the factory address.
function _factory() internal view virtual returns (address factory_) {
return address(uint160(uint256(_getSlotValue(FACTORY_SLOT))));
}
/// @dev Returns the implementation address.
function _implementation() internal view virtual returns (address implementation_) {
return address(uint160(uint256(_getSlotValue(IMPLEMENTATION_SLOT))));
}
}
SlotManipulatable.sol 22 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;
abstract contract SlotManipulatable {
function _getReferenceTypeSlot(bytes32 slot_, bytes32 key_) internal pure returns (bytes32 value_) {
return keccak256(abi.encodePacked(key_, slot_));
}
function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) {
assembly {
value_ := sload(slot_)
}
}
function _setSlotValue(bytes32 slot_, bytes32 value_) internal {
assembly {
sstore(slot_, value_)
}
}
}
IProxied.sol 31 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;
/// @title An implementation that is to be proxied, must implement IProxied.
interface IProxied {
/**
* @dev The address of the proxy factory.
*/
function factory() external view returns (address factory_);
/**
* @dev The address of the implementation contract being proxied.
*/
function implementation() external view returns (address implementation_);
/**
* @dev Modifies the proxy's implementation address.
* @param newImplementation_ The address of an implementation contract.
*/
function setImplementation(address newImplementation_) external;
/**
* @dev Modifies the proxy's storage by delegate-calling a migrator contract with some arguments.
* Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled.
* @param migrator_ The address of a migrator contract.
* @param arguments_ Some encoded arguments to use for the migration.
*/
function migrate(address migrator_, bytes calldata arguments_) external;
}
IDefaultImplementationBeacon.sol 10 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;
/// @title An beacon that provides a default implementation for proxies, must implement IDefaultImplementationBeacon.
interface IDefaultImplementationBeacon {
/// @dev The address of an implementation for proxies.
function defaultImplementation() external view returns (address defaultImplementation_);
}
Read Contract
HUNDRED_PERCENT 0x6ed93dd0 → uint256
PRECISION 0xaaf5eb68 → uint256
accountedInterest 0x546ef145 → uint112
accruedInterest 0x45fe329f → uint256
assetsUnderManagement 0xf6de0bd2 → uint256
domainStart 0x165b0a9c → uint40
factory 0xc45a0155 → address
fundsAsset 0x39ba9f86 → address
impairmentFor 0x4189182e → uint40, bool
implementation 0x5c60da1b → address
issuanceRate 0x3c9ae2ba → uint256
paymentFor 0x09be15e0 → uint24, uint24, uint40, uint168
poolManager 0xdc4c90d3 → address
principalOut 0xac641655 → uint128
unrealizedLosses 0x67e2ba23 → uint128
Write Contract 13 functions
These functions modify contract state and require a wallet transaction to execute.
callPrincipal 0xd97aea12
address loan_
uint256 principal_
claim 0x0827b071
int256 principal_
uint256 interest_
uint256 delegateServiceFee_
uint256 platformServiceFee_
uint40 nextPaymentDueDate_
fund 0x23024408
address loan_
impairLoan 0x20d61476
address loan_
migrate 0xc3fbb6fd
address migrator_
bytes arguments_
proposeNewTerms 0xdac83f8d
address loan_
address refinancer_
uint256 deadline_
bytes[] calls_
rejectNewTerms 0x37fdb36f
address loan_
address refinancer_
uint256 deadline_
bytes[] calls_
removeCall 0x9e5d9942
address loan_
removeLoanImpairment 0x1cd8d07b
address loan_
setImplementation 0xd784d426
address implementation_
triggerDefault 0x40504ba0
address loan_
address liquidatorFactory_
returns: bool, uint256, uint256
triggerDefault 0xffb43a5f
address loan_
returns: uint256, uint256
upgrade 0x3b99bcee
uint256 version_
bytes arguments_
Recent Transactions
No transactions found for this address