Platform: Code4rena
Start Date: 08/01/2024
End Date: 18/01/2024
Period: 10 days
Status: Completed
Pot Size: $83,600 USDC
Participants: 116
Reporter: PaperParachute and
Judge: 0xean
Id: 317
League: ETH
sin1st3r__ | 1/116 | $4,493.00 | 6 | 2 | 0 | 4 | 1 | 0 | 0 | 0 |
juancito | 2/116 | $4,065.97 | 9 | 3 | 0 | 5 | 0 | - | 0 | 0 |
EV_om | 3/116 | $3,730.94 | 8 | 3 | 0 | 5 | 0 | 0 | 0 | 0 |
said | 4/116 | $3,124.22 | 6 | 1 | 0 | 5 | 0 | 0 | 0 | 0 |
hash | 5/116 | $2,733.70 | 9 | 4 | 0 | 5 | 0 | 0 | 0 | 0 |
0xDING99YA | 6/116 | $2,718.28 | 5 | 3 | 0 | 2 | 0 | 0 | 0 | 0 |
DeFiHackLabs | 7/116 | $2,601.84 | 2 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
Beepidibop | 8/116 | $1,873.13 | 4 | 3 | 0 | 1 | 0 | 0 | 0 | 0 |
fnanni | 9/116 | $1,706.97 | 3 | 2 | 0 | 1 | 0 | 0 | 0 | 0 |
AkshaySrivastav | 10/116 | $1,514.23 | 6 | 2 | 0 | 3 | 0 | - | 0 | 0 |
Auditor per page
The 4naly3er report can be found here.
Automated findings output for the audit can be found here within 24 hours of audit opening.
Note for C4 wardens: Anything included in this
Automated Findings / Publicly Known Issues
section is considered a publicly
known issue and is ineligible for awards.
Hook contracts are middleware that execute arbitrary logic before the transaction payload originating from a rental safe executes at an intended target address. As such, this leaves plenty of space for unintended behavior if a malicious or faulty hook contract is used.
This protocol relies on a whitelist which only enables permissioned hook contracts to interact as middleware within the protocol. Therefore, any exploits carried out via logic within a custom hook contract are considered to be known issues.
The Guard contract can only protect against the transfer of tokens that faithfully implement the ERC721/ERC1155 spec. A dishonest implementation that adds an additional function to transfer the token to another wallet cannot be prevented by the protocol. Therefore, these issues are considered to be known.
The protocol contracts do not expect to be interacting with any ERC20 token balances that can change during transfer due to a fee, or change balance while owned by the PaymentEscrow contract. Therefore, these issues are considered to be known.
This protocol facilitates generalized collateral-free NFT rentals built on top of Gnosis Safe and Seaport.
To give an example, imagine Alice has gaming NFTs. She signs seaport order typed data and thus signals that she is happy to lend out these assets. Now, Bob would love to use the NFTs in the game. He finds Alice's listing and rents. This is where these contracts come into force. A gnosis safe is created for Bob where assets he rented get sent to. There is a gnosis module that disallows Bob to move out the assets from his smart contract wallet. He is now free to use the NFTs in-game.
The Default Framework is used as the main architecture for the protocol, and the contracts in scope can be categorized into four main groups:
Modules are internal-facing contracts that store shared state across the protocol. For more information on modules, see here.
Policies are external-facing contracts that receive inbound calls to the protocol, and route all the necessary updates to data models via Modules. For more information on policies, see here.
Packages are small, helper contracts dedicated to performing a single task which are imported by other core contracts in the protocol.
These are general-purpose contracts which are agnostic to the core functionality of the protocol.
Contact | Discord | Telegram | |
---|---|---|---|
Alec | Alec1017 | alecdifederico | alecdifederico |
Naz | nazariyv | nazariyv | AlgorithmicBot |
See scope.txt
Contract | SLOC | Purpose |
---|---|---|
src/modules/PaymentEscrow.sol | 156 | Escrows rental payments while rentals are active. |
src/modules/Storage.sol | 106 | Maintains all the storage for the protocol. |
src/packages/Accumulator.sol | 46 | Implements functionality for managing dynamically allocated data struct arrays directly in memory. |
src/packages/Reclaimer.sol | 41 | Retrieves rented assets from a wallet contract once a rental has been stopped, and transfers them to the proper recipient. |
src/packages/Signer.sol | 195 | Contains logic related to signed payloads and signature verification when creating rentals. |
src/policies/Admin.sol | 58 | Admin duties include fee management, proxy management, and whitelist management. |
src/policies/Create.sol | 365 | Acts as an interface for all behavior related to creating a rental. |
src/policies/Factory.sol | 78 | Acts as an interface for all behavior related to deploying rental safes. |
src/policies/Guard.sol | 161 | Acts as an interface for all behavior related to guarding transactions that originate from a rental wallet. |
src/policies/Stop.sol | 162 | Acts as an interface for all behavior related to stoping a rental. |
src/Create2Deployer.sol | 44 | Deployment contract that uses the init code and a salt to perform a deployment. |
src/Kernel.sol | 251 | A registry contract that manages a set of policy and module contracts, as well as the permissions to interact with those contracts. |
Fee on transfer and rebasing ERC20 tokens are not supported
All ERC20 tokens supported by Seaport are supported here.
There are no restrictions placed on what 721/1155 tokens protocol can interact with. Similarly to ERC20 token support, all tokens supported by Seaport are supported here.
Which blockchains will this code be deployed to, and are considered in scope for this audit?
We are going to launch on: Ethereum Mainnet, Polygon and Avalanche to begin with. We will then look to expand to all the chains that are supported by Safe.
SEAPORT
: Addresses granted this role will be allowed to interact with the
validateOrder()
function in the Create Policy. This is a singleton role that
should only be granted to the Seaport core contract.CREATE_SIGNER
: Addresses granted this role are considered protocol signers
which can sign off on payloads wishing to initiate a rental.ADMIN_ADMIN
: Addresses granted this role are considered admins of the Admin
Policy, and can conduct admin operations on the protocol.GUARD_ADMIN
: Addresses granted this role can toggle whitelisted hook
contracts and which addresses are safe for a rental wallet to delegate callAdditional descriptions of protocol behavior can be found here.
One of the hallmarks of the protocol is that users should be able to safely rent out their assets to rental wallets. These rental wallets should not be allowed to move these assets freely. Potential attack surfaces include usage of delegate call, use of a prohibited function selector, use of a prohibited gnosis safe module, or inability for the protocol to retrieve the asset from the rental wallet once the rental has expired.
Rentals are first transferred to the rental wallet during the processing of a seaport order. Afterwards, a rental is handled by this protocol and logged in storage. A potential attack vector is the prevention of storing the identifier of the rental in storage. If the protocol doesn't know the rental exists, then there is no way to keep the asset in the rental wallet.
Once a rental has expired, any address can initiate the reclaiming process to give rented assets back to the lender, and payments to their intended recipients. A potential attack vector is the breaking of these invariants where lenders may not receive their expected assets back, or payments (denominated in ERC20 tokens) are not given to the proper addresses or in the correct amounts.
setGuard()
enableModule()
or disableModule()
unless the target has been whitelisted by the
Admin Policyapprove()
,
setApprovalForAll()
, safeTransferFrom()
, transferFrom()
, or
safeBatchTransferFrom()
Clone with recurse:
git clone https://github.com/code-423n4/2024-01-renft.git --recurse
Alternatively, if you have already cloned without recurse, do:
git submodule update --init --recursive
This protocol uses Foundry to run tests. To get started:
curl -L https://foundry.paradigm.xyz | bash foundryup
Install all dependencies:
forge install
Run tests:
forge test
Run tests with a gas report:
forge test --gas-report
For an overview of the testing suite, please refer to this doc.
If forge fails to run, please confirm you are running the latest version. This was tested with forge
0.2.0
.
Make sure slither is installed:
pip3 install slither-analyzer
To run static analysis on the contracts:
slither .
We have run default detectors with Slither and posted the output along with our responses to each. Please do not submit these findings unless you have reason to believe our responses here are not valid.
Low severity detectors are not provided, and neither are their explicit justifications