- Total Prize Pool: $41,600 in USDC
- HM awards: $33,100 in USDC
- QA awards: $1,400 in USDC
- Judge awards: $4,000 in USDC
- Validator awards: $2,600 USDC
- Scout awards: $500 in USDC
- Join C4 Discord to register
- Submit findings using the C4 form
- Read our guidelines for more details
- Starts June 14, 2024 20:00 UTC
- Ends June 21, 2024 20:00 UTC
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.
- For whitelisted users, max address cap is set as 3 ETH, but we're calculating the ETH amount(used to buy vultisig tokens) from the
beforeTransferHook
which only has the amount of vultisig tokens. So, to calculate the ETH amount, we're using Univ3 TWAP oracle and applied 5% slippage. So it will be slightly different from the actual ETH amount buyers spent. - Small wei of token amount can be left in contract due to rounding.
Vultisig is a multi-chain, multi-platform, threshold signature vault/wallet that requires no special hardware. It supports most UTXO, EVM, BFT and EdDSA chains. Based on Binance tss-lib, but adapted for mobile environment. It aims to improve security through multi-factor authentication while improving user onboarding and wallet management. This eliminates the need for the user to secure a seed phrase and improves on-chain privacy with multi-party computation archived with the Threshold Signature Scheme.
- Previous audits: None
- Documentation: https://docs.vultisig.com/
- Official project documentation:
- ILO management and token launch plans:
- Website: https://vultisig.com/
- X/Twitter: https://x.com/vultisig
- Discord: https://discord.com/invite/54wEtGYxuv
See scope.txt
File | Logic Contracts | Interfaces | SLOC | Purpose | Libraries used |
---|---|---|---|---|---|
/hardhat-vultisig/contracts/Vultisig.sol | 1 | **** | 14 | @openzeppelin/contracts/token/ERC20/ERC20.sol @openzeppelin/contracts/access/Ownable.sol |
|
/hardhat-vultisig/contracts/Whitelist.sol | 1 | **** | 130 | @openzeppelin/contracts/access/Ownable.sol | |
/hardhat-vultisig/contracts/extensions/VultisigWhitelisted.sol | 1 | **** | 18 | ||
/hardhat-vultisig/contracts/oracles/uniswap/UniswapV3Oracle.sol | 1 | **** | 26 | @uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol | |
/hardhat-vultisig/contracts/oracles/uniswap/uniswapv0.8/FullMath.sol | 1 | **** | 55 | ||
/hardhat-vultisig/contracts/oracles/uniswap/uniswapv0.8/OracleLibrary.sol | 1 | **** | 46 | @uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol | |
/hardhat-vultisig/contracts/oracles/uniswap/uniswapv0.8/TickMath.sol | 1 | **** | 172 | ||
/src/ILOManager.sol | 1 | **** | 170 | @uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol @uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol @uniswap/v3-core/contracts/libraries/TickMath.sol @openzeppelin/contracts/access/Ownable.sol @openzeppelin/contracts/proxy/Clones.sol |
|
/src/ILOPool.sol | 1 | **** | 331 | @uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol @uniswap/v3-core/contracts/libraries/FixedPoint128.sol @uniswap/v3-core/contracts/libraries/FullMath.sol @openzeppelin/contracts/token/ERC721/ERC721.sol |
|
/src/base/ILOPoolImmutableState.sol | 1 | **** | 17 | ||
/src/base/ILOVest.sol | 1 | **** | 36 | ||
/src/base/ILOWhitelist.sol | 1 | **** | 41 | @openzeppelin/contracts/utils/EnumerableSet.sol | |
/src/base/Initializable.sol | 1 | **** | 16 | ||
/src/base/LiquidityManagement.sol | 1 | **** | 44 | @uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol @uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol @uniswap/v3-core/contracts/interfaces/callback/IUniswapV3MintCallback.sol |
|
/src/base/Multicall.sol | 1 | **** | 19 | ||
/src/base/PeripheryPayments.sol | 1 | **** | 25 | @openzeppelin/contracts/token/ERC20/IERC20.sol | |
/src/libraries/ChainId.sol | 1 | **** | 8 | ||
/src/libraries/LiquidityAmounts.sol | 1 | **** | 47 | @uniswap/v3-core/contracts/libraries/FullMath.sol @uniswap/v3-core/contracts/libraries/FixedPoint96.sol @uniswap/v3-core/contracts/libraries/SqrtPriceMath.sol |
|
/src/libraries/PoolAddress.sol | 1 | **** | 32 | ||
/src/libraries/PositionKey.sol | 1 | **** | 10 | ||
/src/libraries/SqrtPriceMathPartial.sol | 1 | **** | 36 | @uniswap/v3-core/contracts/libraries/FullMath.sol @uniswap/v3-core/contracts/libraries/UnsafeMath.sol @uniswap/v3-core/contracts/libraries/FixedPoint96.sol |
|
/src/libraries/TransferHelper.sol | 1 | **** | 34 | @openzeppelin/contracts/token/ERC20/IERC20.sol | |
Totals | 22 | **** | 1327 |
See out_of_scope.txt
File |
---|
./hardhat-vultisig/contracts/interfaces/IApproveAndCallReceiver.sol |
./hardhat-vultisig/contracts/interfaces/IOracle.sol |
./hardhat-vultisig/contracts/interfaces/IWhitelist.sol |
./hardhat-vultisig/contracts/mocks/ApprovalReceiver.sol |
./hardhat-vultisig/contracts/mocks/MockOracleFail.sol |
./hardhat-vultisig/contracts/mocks/MockOracleSuccess.sol |
./hardhat-vultisig/contracts/mocks/MockWhitelistFail.sol |
./hardhat-vultisig/contracts/mocks/MockWhitelistSuccess.sol |
./hardhat-vultisig/contracts/mocks/WETH9.sol |
./script/Common.s.sol |
./script/Deploy.s.sol |
./script/Init.s.sol |
./script/Verify.s.sol |
./src/interfaces/IILOManager.sol |
./src/interfaces/IILOPool.sol |
./src/interfaces/IILOPoolImmutableState.sol |
./src/interfaces/IILOSale.sol |
./src/interfaces/IILOVest.sol |
./src/interfaces/IILOWhitelist.sol |
./src/interfaces/IMulticall.sol |
./src/interfaces/external/IERC1271.sol |
./src/interfaces/external/IERC20PermitAllowed.sol |
./src/interfaces/external/IWETH9.sol |
./test/ILOManager.t.sol |
./test/ILOPool.t.sol |
./test/IntegrationTestBase.sol |
./test/Mock.t.sol |
Totals: 27 |
Question | Answer |
---|---|
ERC20 used by the protocol | Any (all possible ERC20s) that complies with ERC20 token behaviors in scope |
Test coverage | Vultisig - Functions: 81.13%, Lines: 63.78% , ILO - Functions: 72.22%, Lines: 71.68% |
ERC721 used by the protocol | None |
ERC777 used by the protocol | None |
ERC1155 used by the protocol | None |
Chains the protocol will be deployed on | Ethereum |
Question | Answer |
---|---|
Enabling/disabling fees (e.g. Blur disables/enables fees) | ✅ |
Pausability (e.g. Uniswap pool gets paused) | ✅ |
Upgradeability (e.g. Uniswap gets upgraded) | ❌ |
Question | Answer |
---|---|
src/ILOPool.sol | EIP721 (or ERC721) |
Vultisig token will be initially listed on UniswapV3(VULT/ETH pool).
Whitelist
contract will handle the initial whitelist launch and after this period, we will set whitelist
contract address in Vultisig contract back to address(0) so tokens will be transferred without any restrictions.
In whitelist
contract, there's checkWhitelist
function which checks if:
- If
from
address is uniswap v3 pool which holds liquidity, then it means, this transfer is thebuy
action. We will apply the following WL logic. But ifto
address isowner
address, then still ignore. Becauseowner
has exclusive access like increase/decrease liquidity as well as collecting fees. - Token purchase is locked or not - Buyer is blacklisted or not - Buyer whitelist index is within allowed index range(starting from 1 and within 1 ~ allowedWhitelistIndex - inclusive) - ETH amount is greater than max address cap(default 3 ETH) or not
Whitelist contract owner can:
- Set locked period
- Set maximum address cap
- Set vultisig token contract
- Set self whitelisted period
- Set TWAP oracle address
- Set blacklisted flag for certain addresses
- Set allowed whitelisted index(Especially when self whitelist is allowed, anyone can just send ETH and get whitelisted slot and each slot will be assigned by an index called
whitelistIndex
. There could be some suspicious actors so owner can add those addresses to the blacklist. In this case, the total whitelisted addresses will bewhitelistCount - blacklistedCount
. So owner can increase allowedWhitelistedIndex by blacklistedCount to make sure that always 1k whitelisted slots are secured.) - Add whitelisted addresses(single address and batched list)
Regarding ILO contracts:
-
ILOPool.saleInfo
: contains infomation for a sale like hard cap(max raise amount), soft cap(min raise amount to launch), max cap per user, sale start, sale end, max sale amount -
ILOPool._vestingConfigs
: contains vesting config for both investor and project. First element will be config for investor. -
ILOManager._initializedILOPools
: ilo pools associated with a project. When launch project, all ilo pools needs to launch successfully, otherwise, it will reverted. When project admin claim refund. it will claim refund for all initialized pools. -
ILOManager owner(trusted role) can extend/set refund deadline to any projects at any time. But after refund triggered or after launch, this is meaningless.
-
Only project admin can init ilo pool for project and claim project refund (sale token deposited into ilo pool)
-
iloPool belongs to only one project. One project can create many ilo pool.
-
iloPool can only launch from manager. only project admin can launch project(aka launch all ilo pool)
-
Anyone can trigger refund when refund condition met.
-
Anyone can launch pool when all condition met.
-
After refund triggered, no one can launch pool anymore.
-
After pool launch, no one can trigger refund anymore.
-
Once project inits, it inits a uniswap v3 pool. That pool address will be used as project id. You cannot change initial price after project is initialized.
-
is there any senario that makes raise and sale token lock forever?
-
For vultisig token contract, we've added
approveAndCall
function which will just handle token approval and transfer within a single transaction. And the actual receiver contract should implementIApproveAndCallReceiver
interface, especiallyreceiveApproval
function. This will be only used for trusted receiver contracts btw.
Role | Description |
---|---|
Vultisig token owner & Whitelist contract owner | - Can set locked period |
- Can set maximum address cap | |
- Can set vultisig token contract | |
- Can set self whitelisted period | |
- Can set TWAP oracle address | |
- Can set blacklisted flag for certain addresses | |
- Can set allowed whitelisted index | |
ILOManager owner | - Can extend/set refund deadline to any projects |
- Can change protocol and performance fees | |
- Can change ilo pool implementation | |
- Can change FeeTaker | |
- Can change default refund deadline offset |
None
The repo contains 2 contract sets. Vultisig contracts are written in Hardhat so you need to npm install
and then use npx hardhat
to compile and run tests for hardhat-vultisig
contracts.
Before compiling the contracts make sure to set VULTISIG_ALCHEMY_KEY
, DEPLOYER_KEY
, VULTISIG_ALCHEMY_MAINNET_KEY
.
E.g.:
npx hardhat vars set DEPLOYER_KEY yourKeyToSet
git clone https://github.com/code-423n4/2024-06-vultisig.git
git submodule update --init --recursive
npm install
cd hardhat-vultisig
npx hardhat test
To run code coverage;
npx hardhat coverage
Secondly, ILO contracts are built by Foundry. So you need to use forge
to build and run the tests as below:
cd src
forge build
forge test
To run code coverage;
forge coverage
Vultisig contracts build and deploy steps are provided here
ILO contracts build and deploy step are provided here
Employees of Vultisig and employees' family members are ineligible to participate in this audit.