- Overview
- Main Contracts
- Libraries
- Verified Contracts
- Mainnet - Deployed 2023-04-03
- Mainnet - Deployed 2023-02-10
- Mainnet - Deployed 2022-12-19
- Gnosis Testnet - Deployed 2023-03-30
- Goerli Testnet - Deployed 2023-02-10
- Gorli Testnet - Deployed 2023-01-09
- Debt DAO Function Registry
- Interfaces
- LineFactory
- SecuredLine
- Spigot
- Escrow
- ABIs
- LineFactory
- SecuredLine
- Spigot
- Escrow
Overview
System & Architecture<< feel like we need more explainers here >>
<< basic basics >>
Master slave architecture with Line of Credit owning submodules - Spigot, Escrow, InterestRate
Ensure modularity and extensibility of integrations, security fixes, and financial covenants without affecting logic of other components of the system.
Line of Credit contract is also designed to be modular with internal functions that get overwritten by adapters for each module. For example _healthcheck gets overwritten by EscrowedLine to check if minimum collateral ratio has been breached.
Generally this type of architecture introduces lots of security risks in solidity mutating state in different contracts. Debt DAO mitigates this risk by following functional programming standards to avoid side effects in all function calls. We generally only change state in external functions and almost always right before the return statement. Overwritten internal functions/modifiers MUST only return early or add extra revert conditions, never create side effects.
Main Contracts
- Spigot.sol
- SecuredLine.sol
- Full SecuredLine dev docs (todo make dev docs and link)
- Only credit agreement currently supported in Debt DAO Marketplace
- Combines core LineOfCredit, SpigotedLine, and EscrowedLine logic for revenue + asset backed debt
- Modifies internal functions to add additional security checks to
_canDeclareInsolvent()
,liquidate()
,_healthcheck()
, and_init()
- LineOfCredit.sol
- Core financial data and business logic for lending agreement
- Allows dynamic interest rate market for borrower by letting lenders compete on rates and tokens lent
- SpigotedLine.sol
- Integration contract between LineOfCredit.sol and Spigot.sol allowing lines to own Spigots. This lets us
- LineOfCredit literally owns revenue streams to repay its own debt
- programmatically adjust revenue split to give Lenders 100% if borrower defaults
- Holds excess revenue tokens claimed from Spigot and credit tokens bought from swapTarget for future repayments, liquidations, or returning to borrower after repayment
- EscrowedLine.sol
- Light wrapper around Escrow contract to liquidate borrower collateral when they go into default
- LineFactory.sol
- Essentially “The Marketplace”. Defines “market regulations” as global system vars that all lenders and borrowers are confined to
- Oracle - defines all tokens allowed to be lent, borrowed, and used as collateral in the credit marketplace
- SwapTarget - The exchange/market maker that will trade all tokens earned as revenue in Spigots to credit tokens owed to lenders
- Arbiter - The neutral 3rd party that facilitates all repayments, liquidations, defaults, refinancing, etc.
Libraries
Verified Contracts
Mainnet - Deployed 2023-04-03
Main Contracts
- LineFactory:
0xc9eF6509A09b92043cedce689DfAA760048aBd7F
- Module Factory:
0x00A3699F677C252CA32B887F9f66621920D392f8
- Arbiter: (debt dao line ops multisig)
0x1E73ADD2B1cd5152217B0A9B6eA58764a6d97FC1
- SwapTarget: (0x exchange proxy)
0xdef1c0ded9bec7f1a1670819833240f027b25eff
- Oracle: (reused from last deployment)
0x5a4AAF300473eaF8A9763318e7F30FA8a3f5Dd48
- ChainlinkFeedRegistry
0x47Fb2585D2C56Fe188D0E6ec628a38b74fCeeeDf
Libs
- LineLib:
0xC4D9D168EbDcc8a44ea6061F33f07d65CEaf5F86
- CreditLib:
0xEDD70e87d9d9756e753D15D4867753353C3b7d7a
- CreditListLib:
0x982b69751Cb47A94edb7210b069aDC91d9B0127C
- SpigotLib:
0xAE7fAa5c6a7c093B83771a1CadCb51D6Dd59F7eb
- SpigotedLineLib:
0x0d8c1dAdBd42e77577fDFEe01E66C334C77eE082
- LineFactoryLib:
0x599ee0b71ff5975b42dfe42fc81e857d571162f8
- EscrowLib:
0x65458395d06A72762C2942BED6Ee902d1cF554A6
Mainnet - Deployed 2023-02-10
Main Contracts
- LineFactory:
0xe725e25961e04E685A573B1587F8297aC233cD07
- ModuleFactory:
0xa968954770Af47881309d99E36d61C725082B48E
- Oracle:
0x5a4AAF300473eaF8A9763318e7F30FA8a3f5Dd48
- ChainlinkFeedRegistry
0x47Fb2585D2C56Fe188D0E6ec628a38b74fCeeeDf
- Arbiter: (debt dao line ops multisig)
0xE9039a6968ED998139e023ed8D41c7fA77B7fF7A
- SwapTarget: (0x exchange proxy)
0xdef1c0ded9bec7f1a1670819833240f027b25eff
Libs
- LineLib:
0x5250c45087cdAA3dACCBe44BdA987A1f7f3edb02
- CreditLib:
0x9dC5F61dc380BbC3fFBF62Ea1d485BB6122AA9dB
- CreditListLib:
0x3986081dE97eaB5128A99c852466728dD1D9b22F
- SpigotLib:
0x143CA632FdD00218A47e6bE8A117a5595c4b5E5f
- SpigotedLineLib:
0x49a04826F704CF2dFCd5d08bE565871B00932b67
- LineFactoryLib:
0x6e0B15415029A3F858Ea9585F50D35E689dCA0Ae
- EscrowLib:
0xcB442FdF4462123A99dA3627D5Ad4115f6323C0e
Mainnet - Deployed 2022-12-19
Main Contracts
- ModuleFactory:
0xC45677cf45080Df035fD4F2df082ae47EacA729e
- LineFactory:
0xd008d9b4e08DCdaF7F68dAe936EF5cb5FB84F3f4
- Oracle:
0x9EAb5422288805b59391D1442e29Fa16a04A0B22
- Arbiter: (debt dao line ops multisig)
0xE9039a6968ED998139e023ed8D41c7fA77B7fF7A
- SwapTarget: (0x exchange proxy)
0xdef1c0ded9bec7f1a1670819833240f027b25eff
Libs
- LineLib:
0x94a5DA097d3f27962980ab1a1761Cd9e7456252E
- CreditLib:
0x8e73667B175887B106A9F803F8b62DeffC11535e
- CreditListLib:
0x446912dF9f54cf08fA4Fe1bDDe9e3e09E39C09Ca
- SpigotLib:
0xf02b1843cae1A65A7CBD14C13251b4ec9fF23d78
- SpigotedLineLib:
0xA43508CEDDBc3067f236f05b98AEa7aad943A467
- LineFactoryLib:
0xdF146a765eA280dFbf1C98163FD894E4695867FB
- EscrowLib:
0x8f6813Ce50a201D77637b8D24E99feAAa6Ab0Bd2
Gnosis Testnet - Deployed 2023-03-30
Main Contracts
- LineFactory:
0x6934fa7c8ce29ac6c14cd707926fa2539b5cf4cc
- ModuleFactory:
0x8d5c73fdcb26691955b5d4754df2648152fb7736
- Oracle:
0x2239f2669625f6744f0dd0b5c924a61ed191123b
- Arbiter: (debt dao line ops multisig)
0x2e1b9B77692D662AF998e98666908BA80Fb8018E
- SwapTarget: (Multicall bc no 0x on Gnosis)
0xa9b742eafef518026a6f4bc8cb2ae3b232ca0cf8
Libraries
- LineLib:
0x00A3699F677C252CA32B887F9f66621920D392f8
- CreditLib:
0x100a23bbdD2F707901A6FBe46e0eDd9860a866d7
- CreditListLib:
0x819866bA0A1581C324d3fB9513ba8a16f6911e33
- SpigotLib:
0x04e91e5728D89e588276F75CE1Cb1Cc87Dfe9F10
- EscrowLib:
0x4c9416dCcC4d66342c7E5f13dE2a5Fa453e4e607
- SpigotedLineLib:
0x0521D80daF43c264B0653DcD8B8072999a64b7Af
- LineFactoryLib:
0xA242F3ddC21031e99ca90dc11B748fB1E132FEd7
Goerli Testnet - Deployed 2023-02-10
Main Contracts
- Module Factory:
0x627Bbf3200EeC7c757289caED46C74AE241be0b0
- LineFactory:
0x400C6ec8B915e5703E043AA646EA5cb225288D6c
- Oracle:
0x7EDe2714Ad78544cb3834a24215Fe5F871ea7B70
- Arbiter: (Thomas)
0x0325C59BA55F6705C2AC6213628222Cf193d423D
- SwapTarget: (MockZeroEx)
0xcb7b9188aDA88Cb0c991C807acc6b44097059DEc
Libs:
- LineLib:
0x3125CB1b18C43896530Ea5f743B6D135fC652307
- CreditLib:
0x544a5646E1EF70dd8aDE296eC362BAd2C11426DC
- CreditListLib:
0x45bC2F4f4ce55ca6b1B02CDc8Bbd359f4b5B5EBF
- SpigotLib:
0x5Fc4B340a51401d07E81962413c48C548777Aa8D
- SpigotedLineLib:
0x08fB2A4ee88Bc96773aA929db95706c5111eA615
- LineFactoryLib:
0x415984f675ba467b3793C198b8CbEff08Af6EB11
- EscrowLib:
0x42af022e0fDe1131a08FFAf5dA1cd58b16f03173
Gorli Testnet - Deployed 2023-01-09
Main Contracts
- Module Factory:
0x70a951E2D2Ee4Fc6D38325AB0e0ED1a789Eb2D8E
- LineFactory:
0x0E81C743aF01Dc8D77A0cC002daE94EB0433399d
- Oracle:
0x7EDe2714Ad78544cb3834a24215Fe5F871ea7B70
- Arbiter: (Thomas)
0x0325C59BA55F6705C2AC6213628222Cf193d423D
- SwapTarget: (MockZeroEx)
0xcb7b9188aDA88Cb0c991C807acc6b44097059DEc
Libs:
- LineLib:
0xec6e736d8774f9949Cb0985cB4cc1ec9224a601c
- CreditLib:
0xDb19FCFe818493ee84Ce33137b0851DE88c9fF13
- CreditListLib:
0x627A8B08F7d0F10F6BDC4Ef668841fb10B3B2b1d
- SpigotLib:
0x78064A7b6259BcE045d377593288273D22459dfe
- SpigotedLineLib:
0x09d811eEab9893d2285b38728574c55401Ea6A9B
- LineFactoryLib:
0xC6805c0B1Ba484128cE97e92CF5ca09d82B3D51e
- EscrowLib:
0x20b7C07AF032C3a999D9CECf804f4D3b9Fac6a3F
Example Contracts
- Mock Revenue Contract:
0x644cb5d8003efdb1840d5c061ec0df592123dd05
TODO integrate bobs comments here into function registry
Debt DAO Function Registry
Contract | Function Name | Modifiers | Description | Risks of Calling | Calls (sequential order DESC) | Called By | Function Signature |
---|---|---|---|---|---|---|---|
Spigot.sol | getOwnerTokens(address token) | view | Returns the amount of Revenue Tokens held by Spigot that the Owner can withdraw. |
| |||
Spigot.sol | getOperatorTokens(address token) | view | Returns the amount of Revenue Tokens held by Spigot that the Operator can withdraw. |
| |||
Spigot.sol | isWhitelisted(bytes4 functionSignature) | view | Returns if the function has been whitelisted across Revenue Contracts for the Operator to call in operate() | ||||
Spigot.sol | getSetting(address revenueContract) | view | Returns the config for a Revenue Contract: - uint8 ownerSplit - % of revenue that goes to Owner. 0 decimals - bytes4 claimFunction - function selector on Revenue Contract to claim revenue - bytes4 transferOwnerFunction - function selector on Revenue Contract to relinquish ownership from Spigot | ||||
Spigot.sol | owner() | view | Returns the address of the current Spigot Owner. |
| |||
Spigot.sol | operator() | view | Returns the address of the current Spigot Operator. |
| |||
Spigoted Line .sol | unused(address token) | view | Returns the amount of Credit Tokens that have been bought with Revenue Tokens from the Spigot and which haven't yet been withdrawn by a Lender or otherwise used by the Borrower to repay. The system ensures that the first Credit Token in the repayment queue is the one being bought. A Line can have multiple Credit Tokens being lent out and borrowed plus multiple Revenue Tokens being escrowed to repay the debt. This variable holds all of these excess tokens | ||||
Line Of Credit.sol | nextInQ() | view | - Retrieves the next id in FIFO Lender repayment queue. - Returns null if no positions currently have debt (no reason to prioritize any Lender so no queue so no “next in queue”) - Returns the next position id in queue and the most up to date financial data on that position as of that block. | ||||
Line Of Credit.sol | interestAccrued(bytes32 id) | view | - | ||||
Line Of Credit.sol | counts() | view | - Returns tuple of current amount of open positions on Line vs total amount of elements in | ||||
Spigot.sol | claimRevenue(address revenueContract, bytes calldata claimData) | ANYONE | Claims Revenue Tokens earned by one or more Revenue Contracts and updates amount claimable by Owner and Operator.
If push payments: When revenue is sent directly to the Spigot without us doing anything. We must calculate how many have been sent to us and disburse. (push payments = | ||||
Spigoted Line .sol | updateOwnerSplit(address revenueContract) | ANYONE | Checks current status of Line and current owner split of Revenue Contract on Line’s Spigot. Based on status will update owner split if necessary.
if Line status is ACTIVE AND owner split isnt the Line’s | ||||
Line Of Credit.sol | init() | ANYONE | - Checks if all Line modules have been initialized properly. Namely checks that Spigot and Escrow contracts marked as collateral are actually owned by the line. - All modules are required to pass back an OK signal. If, and only if, all modules pass the check then the Line sets its status to ACTIVE and lenders and borrowers can start transacting on the contract. | ||||
Line Of Credit.sol | accrueInterest() | ANYONE | - Accrues interest across all positions currently open on the Line and updates state. | - Borrower can repeatedly call to cause rounding down when calculating interest. According to our math, the gas costs of such an attack is mitigated due to pure gas price costs even for 1 position. This attack vector becomes more expensive the more Lenders so most feasible when only 1 Lender. | |||
Line Of Credit.sol | healthcheck() | ANYONE | - Checks all covenants programmed into Line contract and returns the current health status of the Line. - If borrower has broken covenants then status will be LIQUIDATABLE, otherwise it will usually be ACTIVE. | ||||
Line Of Credit.sol | depositAndRepay(uint256 amount) | ANYONEwhileBorrowing | - Takes funds from callers wallet to repay Borrower’s debt. MUST repay next position in payment queue. - Can be called by anyone not just Borrower. | - ANYONE can repay so you might accidentally repay someone else’s debt | |||
Line Of Credit.sol | updateOutstandingDebt() | ANYONE | - Total debt owed by Borrower across all positions. Returns a tuple of (totalPrincipal, totalInterest). - Denominated in USD and 8 decimals. - Updates state with new interest accrued. | ||||
Line Factory.sol | deploySpigot(address owner, address borrower, address operator) | ANYONE | Deploys a new Spigot with provided config and starts tracking it in the Debt DAO subgraph. | ||||
Line Factory.sol | deployEscrow(uint32 minCRatio, address owner, address borrower) | ANYONE | Deploys a new Escrow with provided config and starts tracking it in the Debt DAO subgraph. | ||||
Line Factory.sol | deploySecuredLine(address borrower, uint256 TTL) | ANYONE | Deploys a new Line of Credit using the arbiter, oracle, | ||||
Line Factory.sol | deploySecuredLineWithConfig(CoreLineParams calldata coreParams) | ANYONE | Deploys a new Line of Credit using the arbiter, oracle for this LineFactory and the provided borrower, term length, | misconfigured | |||
Line Factory.sol | deploySecuredLineWithModules(
CoreLineParams calldata coreParams,
address mSpigot,
address mEscrow
) | ANYONE | Deploys a new Line of Credit using existing Spigot and Escrow contracts that have already been configured. | misconfigured | |||
Line Factory.sol | rolloverSecuredLine(address oldLine, address borrower, uint256 TTL) | ANYONE | Takes debt terms for an existing Line of Credit, copies them and deploys a new Line of Credit for a new (or same) borrower and term length. After this call succeeds, Borrower can call | ||||
Line Of Credit.sol | addCredit(uint128 dRate, uint128 fRate, uint256 amount, address token, address lender) | mutualConsentonlyLenderOrBorrowerwhileActive |
| - Could approve malicious token that can steal your funds (ass borrower or lender) - Create proposal with wrong terms (e.g. interest rate = 0%) that counterparty immediately accepts to exploit your fat finger mistake. - May add volatile token which could cause borrower to be liquidated while borrowing if price moves against them - | |||
Line Of Credit.sol | increaseCredit(bytes32 id, uint256 amount) | mutualConsentonlyLenderOrBorrowerwhileActive | Must have gone through | ||||
Line Of Credit.sol | setRates(bytes32 id, uint128 dRate, uint128 fRate) | mutualConsentonlyLenderOrBorrower | Allows Borrower and Lender to agree to change the drawn rate and/or facility rate on an existing position. | ||||
Line Of Credit.sol | mutualConsent(address signerOne, address signerTwo) | mutualConsent | Internal util function that allows for arbitrary 2/2 multisigs with dynamic participants on any function in our contract. Requires 2 different addresses to be signers and the exact same | ||||
Line Of Credit.sol | borrow(bytes32 id, uint256 amount) | onlyBorrowerwhileActive | Must have gone through | ||||
Line Of Credit.sol | depositAndClose() | onlyBorrowerwhileBorrowing | Takes funds from Borrower’s wallet to fully repay all outstanding debt and interest on position and then closes position permanently. MUST repay and close next position in payment queue | ||||
Line Of Credit.sol | close(bytes32 id) | onlyBorrower | Allows Borrower to close any position with no outsanding debt. Takes funds from Borrower’s wallet to repay accrued facility fee and then closes position permanently. | ||||
Secured Line.sol | rollover(address newLine) | onlyBorrower | Helper function to allow Borrower to easily transfer settings and collateral from this line to a new line. Useful after ttl has expired and want to renew Line with minimal effort. Transfers Spigot and Escrow ownership to newLine. Arbiter functions on this Line will no longer work. The new, uninitialized Line deployed by borrower | ||||
Spigoted Line .sol | claimAndRepay() | onlyArbiter | Claims Revenue Tokens from the Spigot as Owner, trades them for Credit Tokens via a DEX and repays debt on next Lender in repayment queue.
Stores any bought Credit Tokens in excess of debt obligation + any leftover Revenue Tokens from trade into the Line’s | ||||
Spigoted Line .sol | claimAndTrade() | onlyArbiter | Claims Revenue Tokens from the Spigot as Owner, trades them for Credit Tokens via a DEX and immediately stores any bought Credit Tokens + any leftover Revenue Tokens from trade into the Line’s | ||||
Spigoted Line .sol | enableSpigot(address revenueContract, ISpigotSettings calldata settings) | onlyArbiter | Calls | Could add a malicious Revenue Contract and/or config that causes funds to be stolen from Spigot. | |||
Spigoted Line .sol | updateWhitelist(address revenueContract, bytes4 operatorFunc) | onlyArbiter | Sets or updates the whitelisted functions that a Borrower (or whoever is Spigot’s Operator) can call on Revenue Contracts so they continue generating revenue while they are collateralized in the Spigot to repay debt. Only callable by an Arbiter. | ||||
Secured Line.sol | liquidate() | onlyArbiter | Forcefully take collateral from Escrow and repay debt for lender. The current implementation just sends "liquidated" tokens to Arbiter to sell off how the deem fit and then manually repay with DepositAndRepay. | ||||
Spigoted Line .sol | addSpigot(address revenueContract, ISpigot.Setting calldata setting) | onlyArbiter | Enables automatic repayment of the loan by diverting revenue from the Borrower’s revenue generating contract/s. | Risk is that you add you revenue contract with incorrect claim transfer ownership selectors making it impossible to claim revenue | |||
Line Of Credit.sol | declareInsolvent() | onlyArbiter | If the borrower is incapable of repaying the loan, there needs to be an attempt to make the lender whole | ||||
Escrow.sol | enableCollateral(address token) | onlyArbiter | Called before a borrower can deposit a token as collateral | ||||
Spigot.sol | addSpigot(address revenueContract, SpigotSettings memory setting) | onlyOwner | Attach a new Revenue Contract to a Spigot. MUST include revenue split + valid | Could add a malicious Revenue Contract and/or config that causes funds to be stolen from Spigot. | |||
Spigot.sol | updateWhitelistedFunction(bytes4 func, bool isAllowed) | onlyOwner | Allows the Owner to update Spigot whitelist of functions Operator can call on Revenue Contracts. This allows Operator to perform managerial tasks on its Revenue Contracts so they continue generating revenue while they are collateralized in the Spigot to repay debt. | Could add a malicious function on Revenue Contract that causes funds to be stolen from Spigot. | |||
Spigot.sol | claimOwnerTokens(address token, uint256 amount) | onlyOwner | Owner withdraws their share of Revenue Tokens that have already been claimed via claimRevenue() | ||||
Spigot.sol | updateOwnerSplit(address revenueContract, uint8 split) | onlyOwner | Changes the revenue split between the Operator and the Owner based upon programmed conditions or otherwise if the Owner and Operator wish to change the split. | ||||
Spigot.sol | updateOwner(address newOwner) | onlyOwner | Puts a new Owner in control the Spigot. | ||||
Spigot.sol | removeSpigot(address revenueContract) | onlyOwner | - Calls | ||||
Spigot.sol | claimOperatorTokens(address token, uint256 amount) | onlyOperator | - Operator withdraws their share of Revenue Tokens that have already been claimed via claimRevenue() | ||||
Spigot.sol | operate(address revenueContract, bytes calldata msgData) | onlyOperator | - Allows an Operator to call the whitelisted functions on its Revenue Contracts attached to the Spigot and carry on its business as usual activities. | ||||
Spigot.sol | updateOperator(address newOperator) | onlyOperator | - Puts a new Operator address in place to interact with the Revenue Contracts if ever this were needed. | ||||
Line Of Credit.sol | revokeConsent(bytes calldata proposalData) | onlyLenderOrBorrower | If either a Borrower or Lender to create a proposed position (or update an existing position) and then changes their mind (e.g. params are wrong / unfavorable) they can revoke their proposal. This means the other party cannot complete the other half of | ||||
Spigoted Line .sol | useAndRepay(address token, uint256 amount) | onlyLenderOrBorrowerwhileBorrowing | Allows the Borrower or next Lender in repayment queue to use Credit Tokens stored in Line’s | ||||
Spigoted Line .sol | releaseSpigot() | onlyArbiterOrBorrower | Transfers ownership of the entire Spigot from the Line of Credit to either the Borrower (if a Line of Credit has been been fully repaid) or to the Arbiter (if the Line of Credit is liquidatable). | ||||
Spigoted Line .sol | sweep() | onlyArbiterOrBorrower | After a loan has been repaid, sends any remaining Revenue Tokens or Credit Tokens from a Spigot to the Borrower. In case of a Borrower default however (loan status = liquidatable), this function serves as a liquidation mechanism that is called in an effort to increase the Lenders' recovery rate and reduce the "loss given default (LGD)” | ||||
Line Of Credit.sol | withdraw(bytes32 id, uint256 amount) | onlyLender | |||||
Interfaces
Most up to date on Github:
LineFactory
SecuredLine
Spigot
Escrow
ABIs
Most up to date on Github: