Platform: Code4rena
Start Date: 01/08/2022
End Date: 06/08/2022
Period: 5 days
Status: Completed
Pot Size: $50,000 USDC
Participants: 133
Reporter: liveactionllama
Judge: Jack the Pug
Id: 151
League: ETH
Lambda | 1/133 | $8,065.14 | 12 | 6 | 0 | 4 | 1 | - | - | 0 |
hansfriese | 2/133 | $5,180.34 | 11 | 2 | 0 | 8 | 1 | - | 0 | 0 |
rbserver | 3/133 | $3,444.55 | 7 | 2 | 0 | 3 | 0 | - | - | 0 |
0x52 | 4/133 | $2,623.57 | 6 | 2 | 0 | 3 | 1 | - | 0 | 0 |
0xA5DF | 5/133 | $2,599.48 | 7 | 2 | 0 | 3 | 1 | - | - | 0 |
indijanc | 6/133 | $2,560.55 | 3 | 1 | 0 | 1 | 1 | - | 0 | 0 |
GalloDaSballo | 7/133 | $1,979.53 | 4 | 1 | 0 | 1 | 1 | - | - | 0 |
wastewa | 8/133 | $1,672.27 | 3 | 2 | 0 | 1 | 0 | 0 | 0 | 0 |
vlad_bochok | 9/133 | $1,466.57 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
byndooa | 10/133 | $1,295.77 | 6 | 2 | 0 | 3 | 0 | - | 0 | 0 |
Auditor per page
Glossary | |
---|---|
Builder | One who contracts for and supervises the construction of real estate. Builders are the one to create projects |
Project | Entity defined by a sum of tasks, a budget. It represents a real estate construction and is linked to a builder, contractor and subcontractor. |
Contractor | One that agrees to furnish materials or perform services at a specified price, especially for construction work. He is invited by a builder on a project. He can assign a subcontractor on project tasks. Builder can act as a contractor. |
Subcontractor | One who agrees to perform the work specified in a project task. He is assigned to the task by the project's contractor. Contractor can act as a subcontractor. |
Community | Entity with an owner and members aiming at providing loans to projects. Members can publish their projects to the community. A project can only be published to one community at a time. |
Community owner | only member able to provide loans to published projects |
Task | Entity defined by a cost, a subcontractor, and a status. a task can be Inactive, Active or Complete. Tasks can be flagged as Allocated when budget for this task has bee provisioned. When subcontractor confirms the assignment on a task it is being flagged as SCConfirmed |
Debt token | ERC20 token mint and burn capable but with disabled transfer. Only the community contract is able to mint and burn these tokens. They represent the debt owned by the builder to the community owner when a loan has been supplied to the builder for a project |
HomeFi | acronym for Home Finance it is the module where all the protocol modules are linked. Addresses of allowed currencies, project factory, community, treasury and dispute contracts are registered there. |
Token Currency | Crypto currencies used for payment by the protocol. For native currencies like ETH or XDAI we use the wrapped version only. |
The focus is to try and find any logic errors or ways to drain funds from the protocol in a way that is advantageous for an attacker at the expense of users with funds invested in the protocol.
Here are some areas that are of interest :
HomeFi protocol is a generalized protocol that provides public, permission less, decentralized financial infrastructure for home finance. Our mission is to make home finance open, accessible and positive-sum for everyone on earth.
The Protocol is divided into modules with different areas of concerns.
All modules are behind proxies. HomeFi Proxy
is responsible for initializing all the modules contract in the correct sequential order and generate upgradable proxy for them.
To improve the user experience of construction professionals using the protocol, we implemented eip-2771 meta transactions thanks to OpenZeppelin base contracts.
Here are some sequence diagrams for the main rigor flows. Home builder will create a project and add tasks to the project. A per task budget is defined. The builder can publish the project to communities he is a member of. Community provide fix APR loans to builders . Thanks to the loan tasks will be funded and each time a subcontractor completes them he will receive the assigned budget. Finally after selling the real estate the builder is able to repay the loan with interest. Of course depending on the step different signatures will be required to execute the transaction onchain. The repayment can be mark as done off chain through an escrow and directly between the community owner (aka lender) and the builder.
First a builder
creates a project
by calling the createProject()
function on HomeFi.
It will trigger the deployment of a new project thanks to the project factory.
Builder
invites a general contractor
. It requires signing data that includes the contractor
address and the project
address by both the contractor
and the builder
. The signatures and data are used to call inviteContractor(bytes _data, bytes _signature)
Builder add tasks to the project. It requires signing data that includes tasks costs, a hash (task metadata), tasks count and the project
address. Both builder
and contractor
have to sign the data. The signatures and data are used to call addTasks(bytes _data, bytes _signature)
Community Owner creates a community by calling createCommunity(bytes _hash, address _currency)
on the community contract where all the communities are registered. It requires the address of the currency used by the community for lending. The currency must be register in HomeFi to be valid. It also requires a hash (community metadata).
Builder
is invited to be a member of that new community by the community owner
. They both have to sign data including the community ID, the new member address and a message hash (the message can be anything). The data and the signatures in the right order is required to call addMember(bytes _data, bytes _signatures)
on the community contract. It will add the builder as a community member allowing its projects to be published in the community.
Builder publishes his project to the community. It requires signing data that
includes community ID, APR, publishing fee and nonce . Both builder
and community owner
have to sign the data. The signatures and data are used to call publishProject(bytes _data, bytes _signature)
.
Note that you cannot submit a project with no total budget. Therefore it requires at least one task with a budget > 0.
Optional the builder can adjust the amount of the loan requested to a community by calling toggleLendingNeeded(uint256 _communityID, address _project, uint256 _lendingNeeded)
Community owner
lends fund to the published project by calling lendToProject(uint256 _cost)
. This call will update accrued interest, mint debt token for the community owner and transfer tokens to the project contract address.
Builder add tasks to the project. It requires signing data that includes tasks costs, a hash (task metadata), tasks count and the project
address. Both builder
and contractor
have to sign the data. The signatures and data are used to call addTasks(bytes _data, bytes _signature)
Contractor
assign tasks to subcontractor
by calling inviteSC(uint256[] _index, address[] _to)
providing tasks ID and subcontractor address. Subcontractor accepts by calling acceptInviteSC(uint256[] _taskList)
.
Tasks need to be funded to be marked as completed. Although it can be funded through the community, the builder can also fund its project by calling directly lendToProject(uint256 _cost)
on the project contract address.
Task is completed by calling setComplete(bytes _data, bytes _signature)
. It requires signing data that includes task ID and the project
address. builder
, contractor
and subcontractor
have to sign the data. If there is no ongoing dispute about that project, task status is updated and payment is made. Indeed tokens are transferred from the project to the subcontractor's address.
Builder
repays the loan by calling repayLender(uint256 _communityID, address _project, int256 _repayAmount)
on community. It will calculate the owned interest and update the remaining debt. This will trigger the burnt of lender's debt and will transfer tokens from builder
to community owner
.
If for instance an offchain repayment occurred, community owner
can trigger reduceDebt(uint256 _communityID, address _project, uint256 _repayAmount, bytes _details)
. It will also calculate the owned interest update the remaining debt and burn community owner
's debt token. Note that no token transfer between builder
and lender
will happen in that case.
git clone https://github.com/code-423n4/2022-08-rigor.git cd 2022-08-rigor
yarn
cp .sample.env .env
yarn compile
yarn test
yarn coverage
All the contracts in this section are to be reviewed. A further breakdown of contracts and their dependencies can be found here
File | nSLOC | SLOC | Lines |
---|---|---|---|
Contracts (7) | |||
contracts/DebtToken.sol | 35 | 55 | 106 |
contracts/ProjectFactory.sol | 37 | 56 | 106 |
contracts/HomeFiProxy.sol 🌀 | 70 | 93 | 231 |
contracts/Disputes.sol 🧮 | 112 | 144 | 273 |
contracts/HomeFi.sol | 117 | 197 | 323 |
contracts/Project.sol 🧮 | 406 | 474 | 911 |
contracts/Community.sol 🧮 | 422 | 569 | 919 |
Libraries (2) | |||
contracts/libraries/SignatureDecoder.sol 🖥🧮🔖 | 34 | 50 | 86 |
contracts/libraries/Tasks.sol | 68 | 86 | 198 |
Total (over 9 files): | 1301 | 1724 | 3153 |
File | nSLOC | SLOC | Lines |
---|---|---|---|
Interfaces (6) | |||
contracts/interfaces/IDebtToken.sol | 8 | 13 | 50 |
contracts/interfaces/IProjectFactory.sol | 9 | 14 | 58 |
contracts/interfaces/IHomeFi.sol | 41 | 64 | 206 |
contracts/interfaces/IDisputes.sol | 45 | 68 | 160 |
contracts/interfaces/IProject.sol | 57 | 87 | 331 |
contracts/interfaces/ICommunity.sol | 114 | 175 | 440 |
Total (over 6 files): | 274 | 421 | 1245 |
The main entry point for the HomeFi Smart Contract ecosystem. Administrative actions are executed through this contract; new project contracts are created from this contract with accompanying ERC721 for each project.
Child contract deployed from HomeFi.sol, Project.sol contains the primary logic around construction project management. Onboarding contractors, fund escrow, and completion tracking are all managed here. Significant multi-signature and meta-transaction functionality is included here.
Technically separate from HomeFi.sol but can only be accessed by HomeFi.sol.
Contains all project publication and lender funding logic. Lenders fund project contracts through Community.sol, and Builders repay lenders through Community.sol as well.
In the event that a contractor (general or sub) does not get their funds and should have received them, or if there is negligence or malfeasance in the relationship between a builder and lender, participants permissioned in the project have the ability to raise a dispute that HomeFi's admins (in our case Rigor) are able to arbitrate to make sure funds arrive in the correct user's wallet.
Used to wrap Ether, USDC, or Dai and collateralize a given project. hTokens are given to lenders in the Community.sol contract as a receipt to track their lending into the project. On an builder's repayment of a project, hTokens are instantly destroyed, and the underlying collateral is returned + interest for the loan duration.
Internal library used in Project. Contains functions specific to a task actions and lifecycle.
Decodes signatures that are encoded as bytes.
Interest on a loan are calculated on the principal only and doesn't include interest on the accrued interest.
When a repayment occurs we first repay the interest and if their is money left the principal is repaid. Afterwards the interest will be calculated on the remaining principal.
Here is some examples on a spreadsheet.
REPORT_GAS=true yarn test
yarn deploy-local
yarn deploy-rinkeby
HomeFiProxy contract stores the proxies for HomeFi, Community, Disputes,
ProjectFactory, and all the three DebtTokens. These proxies' implementation can be upgraded individually. Only the admin
can upgrade implementations.
All proxies are stored in an array inside HomeFiProxy with a bytes2 name associated to them.
Contract Proxy | Bytes2 Name |
---|---|
HomeFi | HF |
Community | CN |
Disputes | DP |
ProjectFactory | PF |
Native Currency Debt Token | DA |
Token Currency 1 Debt Token | US |
Token Currency 2 Debt Token | NT |
This is valid for all HomeFi proxies- HomeFi, Community, Disputes, ProjectFactory, and DeptTokens.
virtual
modifier to all the functions of old implementation(V1) that are needed to be upgraded.override
modifier when overriding a V1 function
or modifier
event
ContractName
V2Mock.sol and its tests inside ./test/utils/contractName
UpgradabilityTests.ts and simply run the Upgradability.ts
test.yarn compile
to compile all contracts, including the new implementation../scripts/upgrade.ts
file, update the following variable accordingly to your deployment:
homeFiProxyAddress
: address of homeFiProxyproxyBytes2Name
: name of the proxy to upgrade. For ex: PF
for ProjectFactor
. Refer ./contracts/HomeFiProxy.sol
for proxies and there name.newImplementationName
: address of the underlying implementation. For ex: address of new ProjectFactory
contract.taskLibraryAddress
: only required when upgrading ProjectFactory
proxy. Address of TaskLibrary
that is linked to Project
contract.upgrade
script,
yarn hardhat run scripts/upgrade.ts --network <your preferred network>
upgrade
script will automatically run the tests
if using the hardhat
network.
Look at various tested V2 mocks inside
./contract/mocks
ProjectFactory proxy upgrade is mostly required to upgrade the underlying Project
contract implementation. To make this upgrade, the new implementation of ProjectFactory
must add a function to change the underlying
address with new Project
implementation. Potentially also updating the interface for Project
contract. Check ./contracts/mock/ProjectFactoryV2Mock.sol
and contracts/mock/ProjectV2Mock.sol
for reference.
Latest contract addresses can be found under "deployments/<network>.json"
- Do you have a link to the repo that the contest will cover? https://github.com/RigorHQ/Rigor-ProtocolV2 - How many (non-library) contracts are in the scope? 7 - Total sLoC in these contracts? 2105 - How many library dependencies? 2 - How many separate interfaces and struct definitions are there for the contracts within scope? 7 interfaces 4 structs - Does most of your code generally use composition or inheritance? We are mostly using Inheritance for storing the basic schema of our contracts. Storing external functions params, returns, events, structs, and enums, without any implementation. - How many external calls? Two. Calling transfer() and transferFrom() on supported tokens. As of now, we are supporting USDC, WXDAI, and WETH. - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol? false - Does it use an oracle? false - Does the token conform to the ERC20 standard? We have a debt token that is a modified ERC20 - Are there any novel or unique curve logic or mathematical models? No - Does it use a timelock function? No - Is it an NFT? We use NFTs - Does it have an AMM? No - Is it a fork of a popular project? false - Does it use rollups? false - Is it multi-chain? false - Does it use a side-chain? false