rabbitholegg / quest-protocol

Quests Protocol is a protocol to distribute token rewards for completing on-chain tasks.
GNU General Public License v3.0
89 stars 23 forks source link

Quest Protocol

Tests Lint

Overview

Quests Protocol is a protocol to distribute token rewards for completing on-chain tasks.

img.png


Table of Contents


Documentation

For more information on all docs related to the Quest Protocol, see the documentation directory here.


Addresses

Mainnet, Optimism, Polygon, Arbitrum, Base, Blast, Mantle and Sepolia:

Contract Name Address
Quest Factory 0x52629961F71C1C2564C5aa22372CB1b9fa9EBA3E
RabbitHole Tickets 0x0D380362762B0cf375227037f2217f59A4eC4b9E
Protocol Rewards 0x168437d131f8deF2d94B555FF34f4539458DD6F9
PowerPass 0xe13fbb9590cb72ba5cc7b0decc9dff8027a7fc9d

Contracts

The main contracts are:

Contract Structure

Contracts are layed out in the following order:

  1. Use statements (i.e. using SafeTransferLib for address;)
  2. Contract storage - we use upgradable architecture so pay special attention to preserving the order of contract storage, and only add to the end.
  3. Contract constructors and initialization functions
  4. Modifiers
  5. External Update functions - anything that modifies contract state
  6. External View Functions - self explanatory
  7. Internal Update functions
  8. Internal View functions

Interfaces should be used to hold the following:

  1. Events
  2. Errors
  3. Structs

Best Practices

For anything not covered here please refer to the Foundry Best Practices for more information.

Patterns

The contracts use two main patterns.

Factory Pattern

More reading here

image

Dependency Injection

More reading here image

Factory Creation Pattern

More reading here


Install

Install dependencies

bun install
forge install

Compile Contracts

forge build

Create .env file

this uses a compromised private key from hardhat's test node, do not use this key for anything other than automated testing!

cp .env.example .env
sed -i '' "s/TEST_CLAIM_SIGNER_PRIVATE_KEY=/TEST_CLAIM_SIGNER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80/" .env

Testing

Run all tests:

forge test

Run a specific test Contract:

Test QuestBudgetTest contracts:

forge test --match-contract QuestBudgetTest

Run test coverage report:

forge coverage --report lcov

Run gas test:

forge snapshot

Gotchas

If you see something like this expected error: 0xdd8133e6 != 0xce3f0005 in Forge logging, your best bet is to search for the hex string (ce3f0005 don't prepend 0x) in Errors.json within the build artifacts - that should have most error strings in it.

If you run into an issue where there isn't enough funds to deploy on Optimism, but the account appears to have sufficient funds, try adding the --legacy tag to the deploy command.


Deployment

  1. Deploy the ProxyAdmin forge script script/ProxyAdmin.s.sol:ProxyAdminDeploy --rpc-url sepolia --broadcast --verify -vvvv
  2. Deploy QuestFactory (this also upgrades it to the latest version, and deployes the latest Quest and Quest1155 implementation contracts) forge script script/QuestFactory.s.sol:QuestFactoryDeploy --rpc-url sepolia --broadcast --verify -vvvv
  3. Deploy RabbitHoleTickets (this also upgrades it to the latest version) forge script script/RabbitHoleTickets.s.sol:RabbitHoleTicketsDeploy --rpc-url sepolia --broadcast --verify -vvvv
  4. Deploy the ProtocolRewards forge script script/ProtocolRewards.s.sol:ProtocolRewardsDeploy --rpc-url sepolia --broadcast --verify -vvvv
  5. Set any storage variables manually if needed
  6. Deploy the QuestBudget forge script script/QuestBudget.s.sol:QuestBudgetDeploy --rpc-url sepolia --broadcast --verify -vvvv

with mantel, add:

--legacy --verifier blockscout --verifier-url "https://explorer.mantle.xyz/api?module=contract&action=verify" if you get (code: -32000, message: invalid transaction: nonce too low, data: None) try rerunning with the --resume flag

with scroll, add:

--legacy --verifier blockscout --verifier-url "https://blockscout.scroll.io/api?module=contract&action=verify"

with optimism, add:

--legacy

verify OZ TransparentProxy

Note: This might not be needed, there is currently a bug in the mantle explorer that prevents it from marking create2 contracts as contracts

forge verify-contract --verifier blockscout --verifier-url "https://explorer.mantle.xyz/api?module=contract&action=verify" --num-of-optimizations 999999 --chain 5000 --compiler-version "0.8.10+commit.fc410830" 0x52629961F71C1C2564C5aa22372CB1b9fa9EBA3E lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy

Upgrading

important: make sure storage layouts are compatible, by running the upgrades-core validate script on the contract you are upgrading, for example: forge clean && forge build && bunx @openzeppelin/upgrades-core validate --contract RabbitHoleTickets

Then to upgrade a contract, run one of the following commands: forge script script/QuestFactory.s.sol:QuestFactoryUpgrade --rpc-url sepolia --broadcast --verify -vvvv forge script script/RabbitHoleTickets.s.sol:RabbitHoleTicketsUpgrade --rpc-url sepolia --broadcast --verify -vvvv forge script script/Quest.s.sol:QuestDeploy --rpc-url sepolia --broadcast --verify -vvvv forge script script/Quest.s.sol:Quest1155Deploy --rpc-url sepolia --broadcast --verify -vvvv

or use xargs to deploy on every chain in one command:

echo "sepolia mainnet arbitrum optimism polygon base blast" | xargs -n 1 -I {} forge script script/QuestFactory.s.sol:QuestFactoryUpgrade --broadcast --verify --rpc-url {}
echo "sepolia mainnet arbitrum optimism polygon base blast" | xargs -n 1 -I {} forge script script/Quest.s.sol:QuestDeploy --broadcast --verify --rpc-url {}
echo "sepolia mainnet arbitrum optimism polygon base blast" | xargs -n 1 -I {} forge script script/Quest.s.sol:Quest1155Deploy --broadcast --verify --rpc-url {}

and for our mantle: forge script script/QuestFactory.s.sol:QuestFactoryUpgrade --broadcast --verify --rpc-url mantle --legacy --verifier blockscout --verifier-url "https://explorer.mantle.xyz/api?module=contract&action=verify"

Note the extra options to use with mantel and scroll above.

If you get a (code: -32000, message: invalid transaction: nonce too low, data: None) error, try running the same command with the --resume flag.


NFT image IPFS CIDs

red animation: bafybeietacfcrgwetjwcexdakfhmig4fgsdsb7o62n2qcpybkbiupqlkxq red image: bafkreiafob6tgwkb4jla5ent7d7rw4ps7tjdhe32tlbdenyrc3lch76qfe blue animation: bafybeib43gbmeloa6o6hs7xxwioyvduohmuf6yyu2avusjuke7delbou3m blue image: bafkreicoysyc5chqjntdpxiyfojoljabycedep3mssphpwv7opfqfrlwbq

https://cloudflare-ipfs.com/ipfs/ is a good public IPFS gateway


Audits

The following auditors reviewed the protocol.


Bug Bounty

All contracts except tests, interfaces, dependencies are in scope and eligible for the Quest Protocol Bug Bounty program.

The rubric we use to determine bug bounties is as follows:

Level Example Maximum Bug Bounty
6. Severe - Draining or freezing of holdings protocol-wide (e.g. draining token distributor, economic attacks, reentrancy, MEV, logic errors) Let's talk
5. Critical - Contracts with balances can be exploited to steal holdings under specific conditions (e.g. bypass guardrails to transfer precious NFT from parties, user can steal their party's distribution) Up to 25 ETH
4. High - Contracts temporarily unable to transfer holdings
- Users spoof each other
Up to 10 ETH
3. Medium - Contract consumes unbounded gas
- Griefing, denial of service (i.e. attacker spends as much in gas as damage to the contract)
Up to 5 ETH
2. Low - Contract fails to behave as expected, but doesn't lose value Up to 1 ETH
1. None - Best practices

Any vulnerability or bug discovered must be reported only to the following email: security@rabbithole.gg.


License

The primary license for the Quest Protocol is the GNU General Public License 3.0 (GPL-3.0), see LICENSE.

Several interface/dependencies files from other sources maintain their original license (as indicated in their SPDX header). All files in test/ remain MIT (as indicated in their SPDX header).