Our Smart Contract Security Principles
- Vyper >>>>
- Foundry >>>>
- Testing methods
- game theory role playing
- unit testing
- integration testing
- fuzzing
- onchain fork testing
- TODO: formal verification
- TODO: agent based modeling simulations
Testing Debt DAO Contracts
# Setup
$ git clone https://github.com/debtdao/Line-of-Credit.git lines
$ cd lines
$ foundryup
$ forge install
# Run all tests
$ forge test -vvv
# Test individual test files
$ forge test —match-path <filepath>
# Test individual tests
$ forge test —match-test <testname>
# Check test coverage
$ forge coverage
Config
Before running tests, make sure the foundry.toml
file is correctly configured. Make sure it includes the following:
[profile.default]
src = 'contracts'
test = 'test'
script = 'scripts'
out = 'out'
libs = [
]
remappings = [
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"chainlink/=lib/chainlink/contracts/src/v0.8/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/"
]
libraries = []
Check the the .env
file includes the following environment variables:
FOUNDRY_PROFILE=""
MAINNET_ETHERSCAN_API_KEY= <YOUR_KEY_HERE>
DEPLOYER_MAINNET_PRIVATE_KEY= <YOUR_KEY_HERE>
MAINNET_RPC_URL= <YOUR_RPC_URL_HERE>
GOERLI_RPC_URL= <YOUR_GOERLI_RPC_URL_HERE>
GOERLI_PRIVATE_KEY= <YOUR_GOERLI_PRIVATE_KEY_HERE>
LOCAL_RPC_URL='http://localhost:8545'
LOCAL_PRIVATE_KEY= <LOCAL_PRIVATE_KEY_HERE>
If FOUNDRY_PROFILE
is not set to to goerli
or mainnet
the tests will fail trying to find deployed libraries. Always set FOUNDRY_PROFILE
to ""
to ensure correct testing. If MAINNET_RPC_URL
is left empty, test files that need a mainnet fork (such as the Dex.t.sol
file, will fail.
Testnet
The simplest way to interact with Debt DAO in a test environment is to connect your wallet and use the app with fauceted funds on a test network. All test markets can be accessed from the app or from cloning/forking the Debt DAO frontend.
To interact with test markets make sure you toggle the chosen network to Goerli. The testnet option is available on app in top right drop-down-menu.
You can grab Goerli ETH here: Goerli Faucet
Certain aspects of the app will appear broken. Many of the Lines of Credit on Goerli use fake tokens that have no. chainlink oracle and thus, no dollar value. Therefore, all the fields that use dollar amount will appear 0.
Unit Testing
We have unit tests written for each public function available in our smart contracts. These tests are divided into files that cluster different features or logical components in our system. Tests are designed to make sure functions perform the expected action under the correct conditions and fail under incorrect conditions. We do invariant and fuzz testing as much as possible.
Each test files sets up the scenario in the setup()
function. This usually creates a Line of Credit, mints tokens to borrowers and lenders as well as instantiating any peripheral contracts that will be interacted with (Oracles, InterestRate Contract).
We use the Foundry Framework for testing, which allows for Solidity based testing. The benefit of this is that the tests more accurately describe the intended functionality of our smart contracts, and allow for more accurate debugging using the -vvv flag. Additionally, it speeds up development by simplifying the steps needed to create tests for new functionality. You can find more detailed documentation on Foundry here: Foundry Docs.
Maintenance is necessary any time read or write functionally is added, or if a function return is altered.
Integration Testing
Several test files test our individual modules integration with each other. Spigoted Line, Escrowed Line, and Secured Line test that the individual Escrow and Spigot modules integrate with our Line of Credit module properly and that the combined module logic operates as expected.
Additionally, we have test files that evaluate our products compatibility with external services, specifically the 0x API , 0x Exchange, and Chainlink oracles.
Onchain Fork Testing
We test all external integration tests on mainnet forks. Additionally we use mainnet forks to test new features and fixes or develop new products on top of our previously deployed contracts.
Primary mainnet tests:
- 0x API offchain API responses execute onchain at the right price
- Chainlink oracle failures cause appropriate error paths in our wrapper contract
- Pool contract integration with underlying Line contracts they invest in
- Pool contract integration with Lines they borrow from
- Pool contract integration with Spigots they attach
Agent-Based Modeling
As we continue to expand our marketplace and integrate with other platforms, it becomes increasingly difficult to test all scenarios. Simple rules can lead to complex behavior and Interoperability leads to increased complexity. Therefore, it becomes necessary to constantly test our products within simulated environments in order to catch potential attack vectors, non-optimal parameter settings and other unforeseen situations.
The goal is to create baseline behaviors with 0 intelligence and optimizing agents and then use Reinforcement Learning Agents to push the boundaries of our system.
Our ABM framework with be written in Python and will leverage XXX and XXX to simulate our Line of Credit and Pools products.
- Types of Agents
- 0 intelligence
- Hard coded, no optimization: buy and sell randomly, 50%. Not changing behavior.
- Optimizing Agent
- They understand how markets work and how other agents work. They do not change their behavior.
- Reinforcement Learning Agents
- Look at their actions and change their behavior
- Try to explore the whole market
Known Edge Cases & Security Risks
In this section, we explain some edge cases and risk situations, whether they are managed and covered automatically, and what the procedure is case by case.
Attack vectors mainly focus around the risk to Lenders' deposits, there are also risks to consider for Borrowers too.
Bounties are available for new stuff so keep digging!
Bad Actor Claiming Revenue Tokens from a Spigot
Negative Impact of Whitelisted functions on the Spigot
Upgradeable Revenue Contract
Attack on Revenue Contract
Intentional Default by Borrower
Malicious Spigot Owner
Borrower Trading Revenue Tokens for a Fake Credit Token
Abuse of Split of Revenue Tokens from a Spigot
Borrower can still claim Revenue Tokens from a Spigot after failing to repay by the end of the term
Malicious Arbiter could transfer Spigot Ownership to a Borrower before a loan has been repaid
Borrower can prevent Lender from withdrawing (and can minimize drawn interest accruing)
Enabling token collateral - internal transaction error
Lender can deposit after Line expiry
Onchain Monitoring
We use OpenZeppelin Defender to run cron jobs and react to onchain events. This includes automated daily reporting sent to our discord, initiating borrower defaults (but not liquidations!), and other simple operational tasks.
Leveraging our Agent Based Modeling simulation framework, we have created edge case scenarios that we want specifically monitor. As our simulation framework advances, the number of
Platform Level Risks
- integrations
- smart contract risks
- trust assumptions
- other assumptions (e.g. spigot isnt hacked == trustless repayment)
Our Auditors
All previous audits
All Debt DAO AuditsOther Resources
[TEMPLATE] Spigot Evaluation [TEMPLATE] Auditor Engagement Debt DAO Security Engagements🚨 🚧 🚧 🚧 🚨 Under Construction 🚨 🚧 🚧 🚧 🚨
Smart Contract TestingABM & GP