Gitcoin Passport - Identity Staking Invitational

Gitcoin Passport is your secure access to the open web, offering a trusted and transparent digital identity solution designed to empower and connect the global community of builders and contributors.

  • Start date6 Mar 2024
  • End date12 Mar 2024
  • Total awards$14,000 in USDC
  • Duration6 days

Gitcoin audit details

  • Total Prize Pool: $14,000 in USDC
    • HM awards: $7,740 in USDC
    • Analysis awards: $430 in USDC
    • QA awards: $215 in USDC
    • Gas awards: $215 in USDC
    • Judge awards: $1,900 in USDC
    • Scout awards: $500 in USDC
    • Mitigation Review: $3,000 in USDC (Opportunity goes to top 3 certified wardens based on placement in this audit.)
  • Join C4 Discord to register
  • Submit findings using the C4 form
  • Read our guidelines for more details
  • Starts March 6, 2024 20:00 UTC
  • Ends March 12, 2024 20:00 UTC

This is a Private audit

This audit repo and its Discord channel are accessible to certified wardens only. Participation in private audits is bound by:

  1. Code4rena's Certified Contributor Terms and Conditions
  2. C4's Certified Contributor Code of Professional Conduct

All discussions regarding private audits should be considered private and confidential, unless otherwise indicated.

Automated Findings / Publicly Known Issues

The 4naly3er report can be found here.

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.


The IdentityStaking protocol allows users to stake amount of tokens (GTC) and lock the stake for a specified duration. After the expiration of the locking period, the stake can be withdrawn or locked again for another period.
The stake is considered to be a gurantee of someones reputation. It is a colateral that users put as a gurantee on their or on someone elses reputation.
Users will be able to claim stamps in the Gitcoin Passport application based on the amount of tokens staked on them, and this stamps will count towards their humanity score.
Users who are misbehaving and trying to cheat the Gitcoin Passport mechanism to get higher humanity scores will be punished by having the respective stakes slashed.

The slashing logic is not part of the IdentityStaking protocol. The misbehaving users will be identified in an off-chain analysis, and the slashing will be executed by calling the slash function of the IdentityStaking protocol.

The rules for slashing:

  • the slashing will be executed on any staked GTC even if the lock period has expired and the GTC has not yet been withdrawn
  • if I have staked GTC on myself, and I have misbehaved, then my stake will be slashed
  • if I have staked GTC on other people, and I have misbehaved, then all my stakes on others will be slashed
  • if someone else has staked GTC on me, and I have misbehaved, then those particular stakes will be slashed

Slashed GTC will be held in the SC for at least a minimum appeal time (burnRoundMinimumDuration), during which time slashed users can appeal the slashing decision. Upon succefull appeal funds can be restored using the release function of the IdentityStaking protocol.

After the appeal time has ended, funds will be burned using the lockAndBurn function from the IdentityStaking protocol, which will transfer the funds to a designated burn address.



  • In the table format shown below, provide the name of each contract and:
    • source lines of code (excluding blank lines and comments) in each For line of code counts, we recommend running prettier with a 100-character line length, and using cloc.
    • external contracts called in each
    • libraries used in each

ContractSLOCPurposeLibraries used
contracts/IIdentityStaking.sol3This contract implements interface for identity staking staking@openzeppelin/*
contracts/IdentityStaking.sol297This contract implements identity stakingna

Out of scope

List any files/contracts that are out of scope for this audit.

ContractSLOCPurposeLibraries used
contracts/test_mocks/GTC.sol205Mock contract for testingna
contracts/test_mocks/SafeMath.sol52Mock contract for testingna
contracts/test_mocks/Upgrade.sol7Mock contract for testingna

Additional Context

An overview of the logic of identity staking has been covered in the Overview section above. Further details of how this was designed is covered in the readme in the id-staking-v2 folder in the sections:

  1. Appendix A: Slashing Rounds
  2. Appendix B: Slashing in Consecutive Rounds
  3. Appendix C: Diagrams

Also gas optimisations and security aspects are outlined here:

  1. Appendix D: Security

This contract will interact with the GTC ERC-20 contract, as the GTC token will be the token that will be staked. GTC is available on:

  • ETH mainnet, the token contract address is: 0xde30da39c46104798bb5aa3fe8b9e0e1f348163f
  • Optimism, the token contract address is: 0x1EBA7a6a72c894026Cd654AC5CDCF83A46445B08

The smart contract will be deployed to ETH Mainnet and Optimism.

The trusted roles are:

  • DEFAULT_ADMIN_ROLE - owner of the SC, authorized to do upgrades
  • PAUSER_ROLE - pause / unpause the smart contract
  • SLASHER_ROLE - authorized to call the slash function
  • RELEASER_ROLE - authorized to release funds frozen for slashing

The smart contract IdentityStaking does not need to comply to any EIP.

The compiler version configured is ^0.8.23 (this already uses unchedked loo increments, so we did not have to do explicit unchecked increments).

Attack ideas (Where to look for bugs)

Our main concern is the safety of the funds in the smart contract:

  • users can only withdraw what they deposited (minus the slashed amount)
  • only users with SLASHER_ROLE role can slash
  • only users RELEASER_ROLE can release
  • only DEFAULT_ADMIN_ROLE can assign roles or upgrade the contract

List specific areas to address - see this blog post for an example

Main invariants

Describe the project's main invariants (properties that should NEVER EVER be broken).

Invariant 1 - total slashed in current or previous round

for round = currentRound or currentRound - 1

totalSlashed[round] = (sum of stake.slashedAmount for all selfStakes and communityStakes where stake.slashedInRound = round)

Invariant 2 - userTotalStaked

userTotalStaked[address] = selfStakes[address].amount + sum(communityStakes[address][x].amount for all x staked on by this address)

Scoping Details

- If you have a public code repo, please share it here:
- How many contracts are in scope?: 1
- Total SLoC for these contracts?: 300
- How many external imports are there?: 5
- How many separate interfaces and struct definitions are there for the contracts within scope?: 1
- Does most of your code generally use composition or inheritance?: Inheritance
- How many external calls?: 9
- What is the overall line coverage percentage provided by your tests?: 100
- Is this an upgrade of an existing system?: False
- Check all that apply (e.g. timelock, NFT, AMM, ERC20, rollups, etc.): Timelock function
- Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: False
- Please describe required context:
- Does it use an oracle?: No
- Describe any novel or unique curve logic or mathematical models your code uses:
- Is this either a fork of or an alternate implementation of another project?: False
- Does it use a side-chain?: False
- Describe any specific areas you would like addressed: na


Provide every step required to build the project from a fresh git clone, as well as steps to run the tests with a gas report.

Running tests

Clone and cd into the id-staking-v2 folder in the repo:
git clone && cd 2024-03-gitcoin/id-staking-v2

Run the tests: npx hardhat test
Run the tests with gas report: REPORT_GAS=true npx hardhat test

Slither warning

Slither will report dangerous comparison: uses timestamp for comparisons (

This issue is known and considered acceptable as explained here: Appendix D: Security


Employees of Gitcoin and employees' family members are ineligible to participate in this audit.