Contract | Function Name | Modifiers | Description | Called When? | Called Why? | Call Does What? | 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. | |||||||
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 = claimFunction == bytes4(0) )
if pull payments: When we must call the Revenue Contract to claim Revenue Tokens and then disburse the amount of tokens received from Revenue Contract. (pull payments = claimFunction == bytes4('0xrealfunc') ) | |||||||
Spigot.sol | addSpigot(address revenueContract, SpigotSettings memory setting) | onlyOwner | Attach a new Revenue Contract to a Spigot. MUST include revenue split + valid transferOwner and claimRevenue functions
SpigotSettings:
- 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 | 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 transferOwnerFunction on Revneu Contract settings and transfers ownership to Operator. | |||||||
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 | 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 | - interestAccrued stored in position data inside Line contract may not always be up to date since state only gets updated when a tx is sent. To view the actual must up to data interest owed on a position we add the existing interestAccrued and call the Line’s interest rate contract to calculate the remaining interest owed up until this block. | |||||||
Line Of Credit.sol | counts() | view | - Returns tuple of current amount of open positions on Line vs total amount of elements in ids array (closed positions are deleted and become null array elements) | |||||||
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 Of Credit.sol | addCredit(uint128 dRate, uint128 fRate, uint256 amount, address token, address lender) | mutualConsentonlyLenderOrBorrowerwhileActive | mutualConsent proposal functionality:
- Requires mutualConsent of Line’s Borrower and the Lender passed in as addCredit params.
- First call to addCredit executes mutualConsent and creates the onchain proposal, second call accepts the onchain proposal and executes addCredit function.
- Lender or Borrower can call in either order. Whoever calls first is proposing the terms to the other.
- Lender and Borrower can call addCredit multiple times with different params to create multiple proposals
- Proposal is not accepted until Borrower AND Lender both send the EXACT same proposal params.
addCredit functionality once proposal is accepted:
- Position data is initialized in contract state with agreed terms
- Lender must approve amount of token before call to accept proposal
- Tokens are transferred from Lenders address to Line contract
- Facility rate interest starts immediately accruing on full Lender deposit
- Borrow must call borrow() to get receive tokens. | - 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 addCredit flow to create position with id already.
Allows Line’s Borrower and position’s Lender to agree to increase total amount of Credit Tokens available to Borrow on that position.
mutualConsent proposal functionality:
- First call to addCredit executes mutualConsent and creates the onchain proposal, second call accepts the onchain proposal and executes increaseCredit function.
- Proposal is not accepted until Borrower AND Lender both send the EXACT same proposal params.
addCredit functionality once proposal is accepted:
- position data is updated in state to increase deposit
- Lender must approve amount of token before call to accept proposal
- Tokens are transferred from Lenders address to Line contract | |||||||
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 msg.data when calling the mutualConsent modified function.
This function is the basis for allowing borrower to have agreements with multiple lenders at the same time. | |||||||
Line Of Credit.sol | borrow(bytes32 id, uint256 amount) | onlyBorrowerwhileActive | Must have gone through addCredit flow to create position with id already.
Allows Line’s Borrower to withdraw funds from specified position.
Borrower starts paying drawn rate and/or facility rate based on position balance.
Position gets sorted into FIFO repayment queue if not already in queue. | |||||||
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. | |||||||
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 | Called when the arbiter has determined that the borrower is incapable of repaying their loan. | Updates the Line’s status to INSOLVENT , after checking that the collateral (if any) has been sold off to cover the loan. | |||||
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 mutualConsent() to create/update the position. This works on only one (1) proposal at a time, if you have made multiple proposals with different terms, you must manually revoke each proposal.
proposalData param is the original msg.data when registering your consent. Must be reconstructed from original data stored offchain and passed in as the ABI encoded function selector + function arguments from addCredit , increaseCredit , or setRates or any other mutualConsent function. This data is used along with the senders address to regenerate the actual proposal ID hash that is then removed from the mutualConsents[] mapping. msg.data is . | Either a Borrower or Lender wants to remove their proposal to create or update a position with specific terms on a Line Of Credit. | Checks that caller is owner of the proposal being revoked and then completely deletes the proposal in storage. | |||||
Line Of Credit.sol | withdraw(bytes32 id, uint256 amount) | onlyLender | ||||||||
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 | |||||||
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 defaultRevenueSplit then calls Spigot to update owner split to default split.
If Line is LIQUIDATABLE AND owner split isnt 100% then calls Spigot to update owner split to 100%.
After setting owner split to 100%, we wait until revenue repayments returns Line status back to ACTIVE where updateOwnerSplit can be called again to set owner split back to the default. | |||||||
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 unusedToken to use in useAndRepay for self-service repayments by Borrowers and Lenders or later trades. | Similar to claimAndTrade() this fn does not “claim” revenue on behalf of the Spigot, instead it can be thought of as “Fetch, Trade, and Repay()”, whereby it fetches revenue tokens (via claimOwnerTokens() ) from the Spigot, trades them using the calldata supplied by the 0x API, and uses LineOfCredit’s _repay() function to adjust the credit’s principal and interest balances. This function calls _accrue | ||||||
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 unusedToken to use in useAndRepay for self-service repayments by Borrowers and Lenders or later trades. | Can be called at any time, but should be called only after claimRevenue() has been called on the Spigot to ensure a non-zero balance for the owner and operator tokens in the Spigot. | The “claim” in the function name can be misleading, and refers to fetching revenue from the Spigot, as opposed to “claiming” revenue from the revenue contract. The credit token first in-line (ie the token of the “active” position) is selected by default as the target token for the trade. The transfer and trading happens in the SpigotedLineLib’s claimAndTrade() function. The owner tokens are claimed (transferred) from the Spigot to the Line, then traded according to the calldata supplied by the 0x API, which is passed in to the function along with the desired claim token. The Line’s unusedTokens[token] balance is increased by the number of tokens purchased in the trade. | |||||
Spigoted Line .sol | enableSpigot(address revenueContract, ISpigotSettings calldata settings) | onlyArbiter | Calls addSpigot on Line’s Spigot to add Revenue Contract config. addSpigot call has to come from Line’s address because it is the owner of the Spigot. | 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. | Called any time. | The only way the borrower (ie the operator of the Line of Credit) can interact with privileged functions on their protocol ( revenue contract ) is via the operate() function on the Spigot. This function internally calls updateWhitelistedFunction() on the Spigot, which calls the selfsame function on the SpigotLib. This updates the whitelistedFunctions mapping. | |||||
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. | Called before or after the borrower and lender have called addCredit(). Revenue cannot be used to repay the loan until a revenue stream has been added to the Line via this function. | Does not add a Spigot Contract (as it was already deployed with the line). Instead, can be thought of as “addRevenueStream” as it adds a revenue stream (contract) to the spigot settings struct. The settings are passed in with the original calldata when called on SpigotedLine, which passes the data to functions of the same name on the Spigot and then the SpigotLib. Settings include the revenue contract’s address, owners split, claim function selector, and transfer function selector. | Risk is that you add you revenue contract with incorrect claim transfer ownership selectors making it impossible to claim revenue | ||||
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 unusedTokens to repay debt. Credit Tokens must have already been claimed/traded in claimAndTrade or claimAndRepay and put in unusedTokens for this call to succeed. | |||||||
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)” | |||||||
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 | |||||||
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. | |||||||
Escrow.sol | enableCollateral(address token) | onlyArbiter | Called before a borrower can deposit a token as collateral | Prevents the use of malicious 4626 tokens and ensures deposited tokens have a valid price feed on the oracle. | Updates the mapping in the EscrowState struct (address → bool) to enable the token. Checks that the token is not native Eth, has the correct decimals, and that an oracle price feed is available. | |||||
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, defaultRevenueSplit , and minCRatio for this LineFactory and the provided borrower and term length. Starts tracking Line in the Debt DAO subgraph. | |||||||
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, defaultRevenueSplit , and minCRatio . Starts tracking Line in the Debt DAO subgraph. | misconfigured defaultRevenueSplit and minCRatio that is too high or low. These are immutable so cant be changed once contract is deployed. | ||||||
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 defaultRevenueSplit and minCRatio that is too high or low. These are immutable so cant be changed once contract is deployed. | ||||||
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 rollover on their Line with their new Line address. | |||||||
#
[](https://www.notion.so/71b1953b5f044fb08c26fb9505b29424)
[](https://www.notion.so/365b30675e2f451b822c1c12927753e3)
[](https://www.notion.so/4a4f648af0df4630889448f882b9011b)
[](https://www.notion.so/9f2b1ee0932543438b119bbb7df66db4)
[](https://www.notion.so/c59cb5a1b1e64811b457ed570d4e01ae)
[](https://www.notion.so/58338bf5a88b473b851e597c43abb32a)
[](https://www.notion.so/13003a53fb504ebcbb8e959306054cb7)
[](https://www.notion.so/cdc95a983cbc49a683f9bfb5b9774d63)
[](https://www.notion.so/0d3518395bfb4571baf87087eb2d88dc)
[](https://www.notion.so/5798f6f5893d422a9bbe6e5f33408029) | ||||||||||