- Total Prize Pool: $300,500 USDC
- HM awards: $215,000 USDC
- ✨ Analysis awards: $12,500 USDC
- QA awards: $6,250 USDC
- Bot Race awards: $10,000 USDC
- Gas report awards: $6,250 USDC
- Judge awards: $30,000 USDC
- Lookout awards: $20,000 USDC
- Scout awards: $500 USDC
- Join C4 Discord to register
- Submit findings using the C4 form
- Read our guidelines for more details
- Starts May 30, 2023 20:00 UTC
- Ends July 5, 2023 20:00 UTC
✨ All participating wardens are encouraged to submit an Analysis prior to the closing date. Guidelines and FAQ 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 the automated findings output is considered a publicly known issue and is ineligible for awards.
There are a couple of known issues that are intended and not in scope for this audit:
- Rebases and Fee-On-Transfer tokens are not supported.
- Ulysses AMM (Ulysses Pools and Ulysses Tokens) only supports tokens with 18 decimals, but Ulysses Omnichain accounting supports tokens with any decimals and converts them to 18 decimals.
- There are contracts that allow to renounce ownership and do not override renounceOwnership function from
solady
library. - In ERC20MultiVotes, the delegateBySig uses ecrecover to allow someone to delegate their votes by signing off-chain. Using ecrecover can return a random signer. This can lead to the random address being delegated to the supplied delegatee, but because delegations need to be larger than zero this is not seen as a security issue. GovernorBravoDelegate also uses this, but it is not in scope.
- Our protocol has permissionless factories where anyonce can create with poison erc20 tokens or add poison erc20 tokens. While contracts generated by these are not in scope, if it does affect other contracts or other balances, it is in scope.
Maia DAO V2 Ecossytem docs that explains the business logic and technical references, can be found here. Docs are split into 4 protocols, in which you will find relevant information about how each of these protocols work in the system.
Recognizing that some wardens may prefer multimedia resources, we've integrated a comprehensive video tutorial into our docs, repo, and code. Designed as an alternative to traditional text-based materials, these videos offer a direct visual approach to system comprehension. You can access these resources on our notion page here.
Maia DAO Ecosystem is made to be a significant increase in capital efficiency and utility for the Maia DAO community from the V1 ecosystem. The V2 ecosystem is made up of 4 protocols: Hermes, Maia, Talos and Ulysses.
Previous Audits by Zellic can be found in the audits folder. There are two audits, each for different parts of the codebase:
Hermes provides significant improvements over V1, which is a soldily fork. There are three ideas behind this model:
- Lockers direct emissions to gauges and receive the revenue of each gauge they vote for, proportional to the amount of votes for that gauge
- Lockers can boost their liquidity farming rewards from gauges by up to 2.5x
- Lockers receive rebases weekly proportional to inflation
One of the improvements made is that instead of veNFTs that are locked for 4 years, every lock is made permanent. Claiming rebases was also substituted with a deposit only ERC4626 tokenized vault, which instead of claiming rebases, the burn (permanent lock) rate is increased. This allows users only to vote once and remove unecessary weekly tasks to optimize their funds.
Hermes also introduced a new gauge system, that accepts any kind of yield. The first gauges to be deployed are the Uniswap V3 gauges, which allow users to stake their NFTs and receive rewards. The gauges also allow users to boost their rewards up to 2.5x.
Maia is the first implementation of the Partner bHermes Vault. It allows users to stake their Maia converting it to vMaia and receive two of the three bHermes utilities deposited in the vault. The utilities are: weight and governance. The third utility is boost, which is not claimable by users, but instead used by Maia's Treasury to host a boost aggregator with Talos Positions to enable further accumulation of hermes.
Talos is decentralized Uniswap V3 Liquidity Management protocol. It allows anyone to create and manage new LPs. These LPs always start 50/50 and if they have a manager, it can call two strategies: rebalancing and reranging. Talos LPs are Uni V3 NFT wrappers, while this is less gas efficient, it allows for easier integrations with other protocols, like staking in Uniswap V3 gauges.
Staked Talos Positions need to be attached to a boost aggregator, anyone can deploy one using Boost Aggregator Factory. This allows users to pool together and share the same boost.
Ulysses is devided in two separate concepts: Virtualized and Unified Liquidity. Virtualized liquidity is made possible by using anycall v7 as our messaging layer and means that an asset deposited from a specific chain, is recognized as a different asset from the "same" asset but from a different chain (ex: arb ETH is different from mainnet ETH). Unified Liquidity then unifies these tokens using a stableswap AMM and then depositing them in a Unified Liquidity Token, which is a Multi-Asset ERC4626 tokenized vault. This allows users to deposit any asset from any chain and receive a 1:1 representation of the underlying assets. These Unified Liquidity Tokens can then be used in any other protocol, like Uniswap v3.
While this audit has the whole V2 ecosytem in scope, there are specific concerns that we would like to highlight for the wardens to pay special attention to. These are:
- omnichain accounting.
- omnichain gas management.
- ulysses AMM and token accounting
- proper reward/bribe management
- brick funds in uniswap v3 staker
- try to game/brick/steal funds from talos positions
- src/gauges/UniswapV3Gauge.sol: Handles rewards for distribution, boost attaching/detaching and accruing bribes for a strategy. This gauge was designed for Uniswap V3 liquidity mining, it is responsible for creating and depositing weekly rewards in UniswapV3Staker. The minimum width represents the minimum range a UniV3 NFT must have to be illegible for staking.
- src/gauges/BaseV2Gauge.sol: Handles rewards for distribution, boost attaching/detaching and accruing bribes for a given strategy.
- src/gauges/factories/BaseV2GaugeManager.sol: Handles the management of gauges and gauge factories.
- src/gauges/factories/UniswapV3GaugeFactory.sol: Handles the creation of new Uniswap V3 gauges and the management of existing ones. Adds and removes gauges, and allows the bribe factory to add and remove bribes to gauges.
- src/gauges/factories/BaseV2GaugeFactory.sol: Handles the creation of new gauges and the management of existing ones. Adds and removes gauges, and allows the bribe factory to add and remove bribes to gauges.
- src/gauges/factories/BribesFactory.sol: Responsible for creating new bribe flywheel instances. Owner has admin rights to add bribe flywheels to gauges.
- src/erc-4626/ERC4626.sol: Minimal ERC4626 tokenized Vault implementation
- src/erc-4626/ERC4626MultiToken.sol: Minimal ERC4626 tokenized Vault multi asset implementation
- src/erc-4626/UlyssesERC4626.sol: Minimal ERC4626 tokenized 1:1 Vault implementation
- src/erc-4626/ERC4626DepositOnly.sol: Minimal Deposit Only ERC4626 tokenized Vault implementation
- src/erc-20/ERC20MultiVotes.sol: an ERC20 extension that allows delegations to multiple delegatees up to a user's balance on a given block.
- src/erc-20/ERC20Boost.sol: This contract is meant to be used to represent a token that can boost holders' rewards in other contracts. Holders can have their boost attached to gauges and cannot transfer their bHermes until they remove their boost. Only gauges can attach and detach boost from a user. The current user's boost and total supply are stored when attaching. The boost is then detached when the user removes their boost or when the gauge is removed. A "gauge" is represented by an address that distributes rewards to users periodically or continuously.
- src/erc-20/ERC20Gauges.sol: This contract is meant to be used to support gauge style votes with weights associated with resource allocation. Only after delegating to himself can a user allocate weight to a gauge. Holders can allocate weight in any proportion to supported gauges. A "gauge" is represented by an address that would receive the resources periodically or continuously. For example, gauges can be used to direct token emissions, similar to Curve or Hermes V1. Alternatively, gauges can be used to direct another quantity such as relative access to a line of credit.
- src/governance/GovernorBravoDelegator.sol: Upgradeable Governance and on-chain execution contract.
- src/governance/GovernorBravoDelegateMaia.sol: Implementation of Maia Ecosystem Governance and on-chain execution.
- src/governance/GovernorBravoInterfaces.sol: Library with Governor Bravo Interfaces.
- src/ulysses-omnichain/ArbitrumBranchBridgeAgent.sol: Used for interfacing with Users/Routers acting as a middleman to access Anycall cross-chain messaging and Port communication for asset management connecting Arbitrum Branch Chain contracts and the root omnichain environment.
- src/ulysses-omnichain/ArbitrumBranchPort.sol: Used to manage the deposit and withdrawal of underlying assets from the Arbitrum Branch Chain in response to Branch Bridge Agents' requests. Manages Bridge Agents and their factories as well as the chain's strategies and their tokens.
- src/ulysses-omnichain/ArbitrumCoreBranchRouter.sol:
Responsible for permissionlessly adding new tokens or Bridge Agents to the system as well as key governance enabled system functions (i.e.
addBridgeAgentFactory
). - src/ulysses-omnichain/MulticallRootRouter.sol: Root Router implementation for interfacing with third party dApps present in the Root Omnichain Environment.
- src/ulysses-omnichain/CoreRootRouter.sol:
Responsible for permissionlessly adding new tokens or Bridge Agents to the system as well as key governance enabled system functions (i.e.
toggleBranchBridgeAgentFactory
). Desingated for Root chain deployment in the Ulysses Omnichain Liqudity System. - src/ulysses-omnichain/RootBridgeAgentExecutor.sol: Contract used for requesting token settlement clearance and executing transaction requests from the branch chains.
- src/ulysses-omnichain/CoreBranchRouter.sol:
Allows users to permissionlessly add new tokens or Bridge Agents to the system. As well as executes key governance enabled system functions (i.e.
addBridgeAgentFactory
). Designated for Ulysses Omnichain Liquidity System branch chain deployment. - src/ulysses-omnichain/RootBridgeAgent.sol: Contract responsible for interfacing with Users and Routers acting as a middleman to access Anycall cross-chain messaging and Port communication for asset management.
- src/ulysses-omnichain/VirtualAccount.sol: A Virtual Account allows users to manage assets and perform interactions remotely while allowing dApps to keep encapsulated user balance for accounting purposes.
- src/ulysses-omnichain/BranchPort.sol: This contract is used to manage the deposit and withdrawal of underlying assets from the Branch Chain in response to Branch Bridge Agents' requests. Manages Bridge Agents and their factories as well as the chain's strategies and their tokens.
- src/ulysses-omnichain/BranchBridgeAgent.sol: Contract for deployment in Branch Chains of Omnichain System, responible for interfacing with Users and Routers acting as a middleman to access Anycall cross-chain messaging and requesting / depositing assets in the Branch Chain's Ports.
- src/ulysses-omnichain/BaseBranchRouter.sol: Base contract for deployment in Branch Chains of the Ulysses Omnichain System, additional logic can be implemented to perform actions before sending cross-chain requests, as well as in response to requests from the Root Omnichain Environment.
- src/ulysses-omnichain/RootPort.sol: Used to manage the deposit and withdrawal of assets between the Root Omnichain Environment an every Branch Chain in response to Root Bridge Agents requests. Manages Bridge Agents and their factories as well as key governance enabled actions such as adding new chains.
- src/ulysses-omnichain/BranchBridgeAgentExecutor.sol: Used for requesting token deposit clearance and executing transactions in response to requests from the root environment.
- src/ulysses-omnichain/token/ERC20hTokenRoot.sol: 1:1 ERC20 representation of a token deposited in a Branch Chain's Port. ERC20 hToken contract deployed in the Root Chain of the Ulysses Omnichain Liquidity System
- src/ulysses-omnichain/token/ERC20hTokenBranch.sol: 1:1 ERC20 representation of a token deposited in a Branch Chain's Port. Is only minted upon user request otherwise underlying tokens are cleared and the matching Root hToken has been burned. Contract designated for deployment in the Branch Chains of the Ulysses Omnichain Liquidity System.
- src/ulysses-omnichain/factories/BranchBridgeAgentFactory.sol: Factory contract for allowing permissionless deployment of new Branch Bridge Agents which are in charge of managing the deposit and withdrawal of assets between the branch chains and the omnichain environment.
- src/ulysses-omnichain/factories/RootBridgeAgentFactory.sol: Factory contract used to deploy new Root Bridge Agents responsible which are in charge of managing the deposit and withdrawal of assets between the branch chains and the omnichain environment.
- src/ulysses-omnichain/factories/ERC20hTokenBranchFactory.sol: Factory contract allowing for permissionless deployment of new Branch hTokens in Branch Chains of Ulysses Omnichain Liquidity Protocol. This contract is called by the chain's Core Branch Router.
- src/ulysses-omnichain/factories/ERC20hTokenRootFactory.sol: Factory contract allowing for permissionless deployment of new Root hTokens in the Root Chain of Ulysses Omnichain Liquidity Protocol. This contract is called by the chain's Core Root Router.
- src/ulysses-omnichain/factories/ArbitrumBranchBridgeAgentFactory.sol: Factory contract for allowing permissionless deployment of new Arbitrum Branch Bridge Agents which are in charge of managing the deposit and withdrawal of assets between the branch chains and the omnichain environment.
- src/ulysses-omnichain/lib/AnycallFlags.sol: Library of Anycall Flags
- src/ulysses-amm/UlyssesRouter.sol: This contract routes and adds/removes liquidity from Ulysses Pools deployed by the Ulysses Factory, it allows users to set maximum slippage.
- src/ulysses-amm/UlyssesToken.sol: ERC4626 multiple token implementation intended for Ulysses Pools. Balances are always 1 : 1 with the underlying assets.
- src/ulysses-amm/UlyssesPool.sol: This contract is stableswap AMM that uses it's implemention of the Delta Algorithm to manage the LP's balances and transfers between LPs.
- src/ulysses-amm/factories/UlyssesFactory.sol: This contract is responsible for creating new Ulysses Tokens and Ulysses Pools.
- src/uni-v3-staker/UniswapV3Staker.sol: Allows staking non-fungible liquidity tokens in exchange for reward tokens.
- src/uni-v3-staker/libraries/RewardMath.sol: Allows computing rewards given some parameters of boost, stakes and incentives.
- src/uni-v3-staker/libraries/NFTPositionInfo.sol: Encapsulates the logic for getting info about a NFT token ID.
- src/uni-v3-staker/libraries/IncentiveId.sol: This library is responsible for computing the incentive identifier.
- src/uni-v3-staker/libraries/IncentiveTime.sol: This library is responsible for computing the incentive start and end times.
- src/rewards/FlywheelCoreInstant.sol: Flywheel Instant is a general framework for managing token incentives that should be accrued atomically. It takes a single reward stream to various strategies such as staking LP tokens and divides them among users of those strategies.
- src/rewards/FlywheelCoreStrategy.sol: Flywheel Strategy is a general framework for managing token incentives. It takes reward streams per strategies such as staking LP tokens and divides them among users of those strategies.
- src/rewards/base/BaseFlywheelRewards.sol: Determines how many rewards accrue to each strategy globally over a given time period.
- src/rewards/base/FlywheelCore.sol: Flywheel is a general framework for managing token incentives. It takes reward streams to various strategies such as staking LP tokens and divides them among users of those strategies.
- src/rewards/rewards/FlywheelBribeRewards.sol: Distributes rewards for allocation to voters at the end of each epoch in accordance to votes.
- src/rewards/rewards/FlywheelGaugeRewards.sol: Distributes rewards from a stream based on gauge weights.
- src/rewards/rewards/FlywheelInstantRewards.sol: This contract is responsible for strategy rewards management. At any moment all the rewards can be accrued from any strategy from the general rewards depot for subsequent distribution. The reward depot serves as a pool of rewards.
- src/rewards/rewards/FlywheelAcummulatedRewards.sol: This contract is responsible for strategy rewards management. Once every cycle all the rewards can be accrued from the strategy's corresponding rewards depot for subsequent distribution. The reward depot serves as a pool of rewards.
- src/rewards/booster/FlywheelBoosterGaugeWeight.sol: The Booster module is an optional module for virtually boosting or otherwise transforming user balances. If a booster is not configured, the strategies ERC-20 balanceOf/totalSupply will be used instead. Boosting logic can be associated with referrals, vote-escrow, or other strategies.
- src/rewards/depots/SingleRewardsDepot.sol: Holds rewards to be distributed by a Flywheel Rewards distributor contract.
- src/rewards/depots/MultiRewardsDepot.sol:
Holds multiple rewards to be distributed to Flywheel Rewards distributor contracts. When
getRewards()
is called by an added flywheel rewards, it transfers its balance of the associated assets to its flywheel rewards contract. - src/rewards/depots/RewardsDepot.sol:
Holds a single reward token to be distributed to Flywheel Rewards distributor contracts. When
getRewards()
is called by an added flywheel rewards, it transfers all of the its balance to the flywheel rewards contract. - src/maia/vMaia.sol: vMaia is an ERC-4626 compliant MAIA token which: distributes bHermes utility tokens (Weight, Governance) and Maia Governance in exchange for staking MAIA. Withdraw is only allowed once per month, during the 1st Tuesday (UTC+0) of the month.
- src/maia/PartnerUtilityManager.sol: When implemented, this contract allows for the partner management of bHermes utility tokens.
- src/maia/factories/PartnerManagerFactory.sol: This contract is used to manage the list of partners and vaults.
- src/maia/tokens/Maia.sol: ERC20 representing a share of the Maia ecosystem.
- src/maia/tokens/ERC4626PartnerManager.sol: Partner Manager is an ERC-4626 compliant Partner token which: distributes bHermes utility tokens (Weight, Boost, Governance) in exchange for staking Partner tokens.
- src/maia/libraries/DateTimeLib.sol: Library for date time operations. To get the current month and check if it is the first Tuesday of the month.
- src/talos/TalosManager.sol: TalosManager is a Uniswap V3 yield enhancement contract which acts as intermediary between the user who wants to provide liquidity to specific pools and earn fees from such actions. The contract ensures that user position is in range and earns the maximum amount of fees available at current liquidity utilization rate.
- src/talos/TalosStrategyVanilla.sol: Tokenized Vault implementation for Uniswap V3 Non Fungible Positions.
- src/talos/TalosStrategyStaked.sol: Tokenized Vault implementation for a staked Uniswap V3 Non-Fungible Positions.
- src/talos/TalosOptimizer.sol: Contains Optimizer variables used by Talos LPs that may only be modified by the governance.
- src/talos/factories/BoostAggregatorFactory.sol: This contract is responsible for creating new BoostAggregators.
- src/talos/factories/TalosStrategyVanillaFactory.sol: This contract is used to create new TalosStrategyVanilla contracts.
- src/talos/factories/TalosStrategyStakedFactory.sol: This contract is used to create new TalosStrategyStaked contracts.
- src/talos/factories/OptimizerFactory.sol: This contract is responsible for creating new Talos Optimizers.
- src/talos/factories/TalosBaseStrategyFactory.sol: This contract is used to create new TalosBaseStrategy contracts.
- src/talos/strategies/TalosStrategySimple.sol: This contract is responsible for rebalacing and reranging strategies for TALOS UniswapV3 LPs.
- src/talos/boost-aggregator/BoostAggregator.sol: This contract is used to aggregate Uniswap V3 NFTs from multiple addresses and stake them in the Uniswap V3 Staker contract, sharing the same boost. This contract allows for boost management and rewards distribution. so users can stake their NFTs and receive boosted hermes rewards.
- src/talos/libraries/PoolVariables.sol: Provides functions for computing liquidity and ticks for token amounts and prices.
- src/talos/libraries/PoolActions.sol: This library is created to conduct a variety of swap, burn and add liquidity methods.
- src/talos/base/TalosBaseStrategy.sol: This contract is responsible for managing a Uniswap V3 Non Fungible Position. TalosBaseStrategy allows the implementation two managing functions: rerange and rebalance. Both these actions are performed according to Talos Optimzer's values. The underlying Uniswap V3 Pool NFT can be staked in any other contract by using internal hooks.
- src/hermes/bHermes.sol: bHermes is a deposit only ERC-4626 for HERMES tokens which: mints bHermes utility tokens (Weight, Boost, Governance) in exchange for burning HERMES.
- src/hermes/UtilityManager.sol: When implemented, this contract allows for the management of bHermes utility tokens.
- src/hermes/tokens/bHermesVotes.sol: Represents the underlying governance power of a bHermes token.
- src/hermes/tokens/HERMES.sol: Native token for the Hermes Incentive System.
- src/hermes/tokens/bHermesGauges.sol: Represents the underlying emission direction power of a bHermes token. bHermesGauges is an ERC-4626 compliant bHermes token which: votes on bribes rewards allocation for Hermes gauges in a manipulation-resistant manner.
- src/hermes/tokens/bHermesBoost.sol: An ERC20 with an embedded attachment mechanism to keep track of boost allocations to gauges.
- src/hermes/minters/BaseV2Minter.sol: Codifies the minting rules as per b(3,3), abstracted from the token to support any ERC4626 with any token that allows minting. Responsible for minting new tokens.
There are specific concerns that we would like to highlight for the wardens to pay special attention to. We highlighted these in the Areas of Concern section above.
- @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
- @openzeppelin/contracts/token/ERC20/IERC20.sol
lib/v3-periphery/contracts/base/PeripheryPayments.sollib/v3-periphery/contracts/base/PeripheryPaymentsWithFee.sollib/v3-periphery/contracts/base/SelfPermit.sollib/v3-periphery/contracts/interfaces/IERC20Metadata.sol- lib/v3-periphery/contracts/interfaces/external/IWETH9.sol
lib/v3-periphery/contracts/libraries/TransferHelper.sol
- @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
- @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
- @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
- @openzeppelin/contracts/token/ERC721/IERC721.sol
- @openzeppelin/contracts/utils/Address.sol
- @openzeppelin/contracts/utils/Strings.sol
- @uniswap/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol
- @uniswap/v3-core/contracts/interfaces/callback/IUniswapV3MintCallback.sol
- @uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol
- @uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol
- @uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol
lib/v3-periphery/contracts/NonfungiblePositionManager.sollib/v3-periphery/contracts/NonfungibleTokenPositionDescriptor.sollib/v3-periphery/contracts/SwapRouter.sollib/v3-periphery/contracts/base/PoolInitializer.sollib/v3-periphery/contracts/lens/Quoter.sollib/v3-periphery/contracts/lens/QuoterV2.sollib/v3-periphery/contracts/lens/TickLens.sollib/v3-periphery/contracts/libraries/CallbackValidation.sollib/v3-periphery/contracts/libraries/NFTDescriptor.sollib/v3-periphery/contracts/libraries/OracleLibrary.sollib/v3-periphery/contracts/libraries/PoolTicksCounter.sollib/v3-periphery/contracts/libraries/PositionValue.sol
- @uniswap/v3-core/contracts/libraries/BitMath.sol
- @uniswap/v3-core/contracts/libraries/FixedPoint128.sol
- @uniswap/v3-core/contracts/libraries/FixedPoint96.sol
- @uniswap/v3-core/contracts/libraries/FullMath.sol
- @uniswap/v3-core/contracts/libraries/SafeCast.sol
- @uniswap/v3-core/contracts/libraries/Tick.sol
- @uniswap/v3-core/contracts/libraries/TickBitmap.sol
- @uniswap/v3-core/contracts/libraries/TickMath.sol
lib/v3-periphery/contracts/SwapRouter.sollib/v3-periphery/contracts/base/LiquidityManagement.sollib/v3-periphery/contracts/lens/Quoter.sollib/v3-periphery/contracts/lens/QuoterV2.sollib/v3-periphery/contracts/libraries/NFTDescriptor.sollib/v3-periphery/contracts/libraries/OracleLibrary.sollib/v3-periphery/contracts/libraries/PositionValue.sol
- @uniswap/v3-core/contracts/libraries/UnsafeMath.sol
- base64-sol/base64.sol
Anything in lib/ and src/out-of-scope/ is out of scope for this audit.
The libraries used in lib/ are: (other libraries are for testing only)
The contracts in src/out-of-scope/ are copies of contracts of the src/governance/ folder, but with different hard-coded parameters. They will be used live, but are not in scope for this audit:
- GovernorBravoDelegateSeverity1.sol
- GovernorBravoDelegateSeverity2.sol
- GovernorBravoDelegateSeverity3.sol
- GovernorBravoDelegateSeverity4.sol
- GovernorBravoDelegateSeverity5.sol
- GovernorBravoDelegator.sol
- GovernorBravoInterfaces.sol
Hermes V2 is based on solidly's ve(3,3), in order to keep the same logic for the voting and boosting power of the users, was added a new logic for the calculation of the boosted rewards for the uniswapV3 positions, which is based on the seconds per liquidty in active range to calculate rewards of the uniswapV3Staker. It is based on the original UniswapV3Staker logic.
The original Uniswap V3 Staker awards positons based on the difference between snapshotCumulativesInside when staked vs when unstaked times the liquidity of the position. By doing this, we get how much liquidity seconds each position is awarded. In Hermes V2 case, all of hermes incentives have a duration of 1 week, so we can calculate the liquidity seconds per week for each position, 1 week being the maximum.
The original curve logic behind calculating boosted rewards for uniswapV3 positions is based on the following formula, found here, in docs:
$Rewards Received = min(UserLiquidity,(40%*UserLiquidity)+(60%TotalLiquidityUserBoostBalance/BoostTotal))$
In order to calculate the boosted rewards for the uniswapV3 positions, we have used the following formula:
More information on Uniswap V3 Gauges and how boost calculation is made, can be found here, in docs.
The Ulysses Pools AMM is an adaptation of the Delta Algorithm put forh by LayerZero, the original paper can be found here.
In short, Ulysses Pools AMM is a stableswap AMM that allows for the creation of N to N pools with different weights, and the ability to change the weights of the pools after creation. In order to make sure no pools is ever in deficit, only new pools can be added to exisitng pools, can never be removed.
Because of all of Ulysses pools are in the same network (Arbitrum), we can avoid the need to keep credits from each pool, unlike the original Delta Algorithm. This allows us to simplify the logic of the algorithm.
Adapted from: Figure 4, this is the pseudocode for the algorithm:
Input: Transaction amount t, destination LP ID d
# On the source LP:
1: aₛ ← aₛ + t
2: bₛ,𝒹 ← bₛ,𝒹 − t
3: for x != s do
4: diffₛ,ₓ ← max(0, lpₛ * wₛ,ₓ − lkbₓ,ₛ)
5: end for
6: Total ← ∑ₓ diffₛ,ₓ
7: for x != s do
8: diffₛ,ₓ ← min(Total, t) * diffₛ,ₓ / Total
9: end for
10: t′ ← t - min(Total, t)
11: for ∀x do
12: bₛ,ₓ ← bₛ,ₓ + diffₛ,ₓ + t′ * wₛ,ₓ
13: end for
14: msg = (t)
15: Send msg to LP d
# On the destination LP:
16: Receive (t) from a source LP
17: if bₛ,𝒹 < t then
18: Reject the transfer
19: end if
20: a𝒹 ← a𝒹 − t
21: bₛ,𝒹 ← bₛ,𝒹 − t
Renalancing fees are a way to incentivize users to rebalance Ulysses Pools. The fees are calculated based on the difference between the current bandwidth (balance dedicated to another pool) of the pool and the target bandwidth (weight * totalsupply) of the pool. More info can be found here, in docs. The fees are calculated as follows:
Rebalancing Fee | Condition |
---|---|
0 | |
Fee Parameters:
Parameter | Value |
---|---|
0.40% | |
99.60% | |
60% | |
5% |
Because the lambda fee parameters in contract are divided by 2, the actual values used in the contract are:
Parameter | Value |
---|---|
0.20% | |
49.80% | |
60% | |
5% |
The fee is calculated as a trapezium with a base of width and a height of height
The formula for the area of a trapezium is (a + b) * h / 2
___________
fee1 + fee2 -->| /|
| / |
|________/ |
fee1 + fee2 * amount-->| /| |
------------- | / | |
max width | / | |
|____/ | |
fee1 -->| | | |
| | | |
|___|____|__|_____
| | |
upper bound 2 | 0
|
bandwidth
max width = upper bound 2
amount = upper bound 2 - bandwidth
h = amount
a = fee1 + (fee2 * amount / max width)
b = fee1
fee = (a + b) * h / 2
= (fee1 + fee1 + (fee2 * amount / max width)) * amount / 2
= ((fee1 * 2) + (fee2 * amount / max width)) * amount / 2
Because lambda1 = fee1 / 2 and lambda2 = fee2 / 2
fee = ((fee1 * 2) + (fee2 * amount / max width)) * amount / 2
= (lambda1 * 2 * amount) + (lambda2 * amount * amount) / max width
= amount * ((lambda1 * 2) + (lambda2 * amount / max width))
When offset (b) is 0, the trapezium is equivalent to a triangle:
The formula for the area of a triangle is a * h / 2
___________
fee1 -->| /|
| / |
|________/ |
fee1 * amount -->| /| |
------------- | / | |
max width | / | |
| / | |
|___/____|__|_____
| | |
upper bound 1 | upper bound 2
|
bandwidth
max width = upper bound 1 - upper bound 2
amount = upper bound 1 - bandwidth
h = amount
a = fee1 * amount / max width
b = 0
fee = (a + b) * h / 2
= fee1 * amount * amount / (2 * max width)
Because lambda1 = fee1 / 2
fee = fee1 * amount * amount / (2 * max width)
= lambda2 * amount * amount / max width
Ulysses Omnichain Liquidity System uses AnycallV7 (https://github.com/anyswap/multichain-smart-contracts/tree/main/contracts/anycall/v7) for cross-chain messaging, it is integrated using the Pay on Destination flag (0x06
), meaning execution gas fees are credited to the recipient contract (Bridge Agent) deducting the gas spent from this contract's executionBudget
kept in the AnycallConfig contract (https://docs.multichain.org/developer-guide/anycall-v7/estimate-fee-pay-fees-on-destination-chain)
- If you have a public code repo, please share it here: [https://twitter.com/MaiaDAOEco](https://github.com/Maia-DAO/maia-ecosystem-monorepo/tree/main)
- How many contracts are in scope?: 191
- Total SLoC for these contracts?: 10997
- How many external imports are there?: 152
- How many separate interfaces and struct definitions are there for the contracts within scope?: 116
- Does most of your code generally use composition or inheritance?: Composition
- How many external calls?: 30
- What is the overall line coverage percentage provided by your tests?: Can't provide accurate information, so 0
- 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: n/a
- Does it use an oracle?: Yes, Uniswap V3 TWAP is used to check for price deviation in Talos positions
- Does the token conform to the ERC20 standard?: true
- Are there any novel or unique curve logic or mathematical models?: Maia DAO's implementation of the Delta Algorithm (from layerzero). Boosted Reward calculation for uniswapV3 positions from curve and uniswapV3Staker respectively.
- Does it use a timelock function?: true
- Is it an NFT?: true
- Does it have an AMM?: true
- Is it a fork of a popular project?: true
- Does it use rollups?: true
- Is it multi-chain?: true
- Does it use a side-chain?: true
Here is an example of a full script to run the first time you build the contracts in Linux:
forge install
forge build
python3 -m venv venv
source venv/bin/activate
pip3 install pycryptodome
python3 init_code_hash.py
deactivate
forge test --gas-report
forge snapshot --diff
Here is an example of a full script to run the first time you build the contracts in Windows: This script is not tested, if you have any issues, please refer to pycruptodome's documentation or try to hash Uniswap V3 Pool's bytecode through another method.
forge install
forge build
python -m venv venv
venv\Scripts\activate.bat
pip install pycryptodome --no-binary :all:
python init_code_hash.py
deactivate
forge test --gas-report
forge snapshot --diff
Default gas prixe is 10,000, but you can change it by adding --gas-price <gas price>
to the command or by setting the gas_price
property in the foundry.toml file.
Tests don't compile with --via-ir, but contracts do and will be deployed with --via-ir. Compilation settings that will be used are in hardhat.config.ts.
Install libraries using forge and compile contracts.
forge install
forge build
Update PoolAddress.sol with correct INIT_CODE_HASH according to latest build. This has to be run everytime UniswapV3Pool is compiled.
The following example runs a scirpt using a python virtual environment in Linux:
python3 -m venv venv
source venv/bin/activate
pip3 install pycryptodome
python3 init_code_hash.py
deactivate
If you wish, you can install the python dependencies globally and run the script:
pip3 install pycryptodome
python3 init_code_hash.py
The following example runs a scirpt using a python virtual environment in Windows: This script is not tested, if you have any issues, please refer to pycruptodome's documentation or try to hash Uniswap V3 Pool's bytecode through the method below.
python -m venv venv
venv\Scripts\activate.bat
pip install pycryptodome --no-binary :all:
python init_code_hash.py
deactivate
If you wish to do this manually or are having issues with the previous scripts. Then please follow these steps (after building at least once):
- Get the bytecode from
out/UniswapV3Pool.sol/UniswapV3Pool.json
. To do this, head over to the file and get the bytecode from the "bytecode" and then "object" field. - Copy this bytecode and use any tool to hash it using keccak-256 function. For example this tool, but please remember to remove the first two characters "0x" and select input type to "hex" (default is string).
Default gas prixe is 10,000, but you can change it by adding --gas-price <gas price>
to the command or by setting the gas_price
property in the foundry.toml file.
Compile contracts again to update PoolAddress.sol bytecode and run tests.
forge test --gas-report
Compile contracts again to update PoolAddress.sol bytecode and check snapshot differece.
forge snapshot --diff
If you encounter any issues, please update slither to 0.9.3, the latest version at the moment.
To run slither from root, please specify the src directory.
slither "./src/*"
We have a slither config file that turns on optimization and adds forge remappings.