Biconomy Hyphen 2.0 contest details
- $71,250 USDT main award pot
- $3,750 USDT gas optimization award pot
- Join C4 Discord to register
- Submit findings using the C4 form
- Read our guidelines for more details
- Starts March 10, 2022 00:00 UTC
- Ends March 16, 2022 23:59 UTC
Hyphen is cross chain token transfer bridge that works by maintaining liquidity pools on each supported chain. In order to do a cross chain transfer, user deposits his funds in liquidity pool on source chain and then off chain hyphen nodes (executors) listen to this deposit event and trigger a transfer transaction on destination chain where funds are transfered from the pool to user receiving address after deducting a transfer fee. This transfer is dynamic in nature and is decided by a bonding curve formulae that depends on total liquidity provided by the LPs and the current available liquidity in the pool.
If user is trying to take funds out from a pool where available liquidity is less than supplied liquidity then transfer fee will be high and vice versa. When available liquidity = supplied liquidity, then transfer fee is equal to equilibrium fee configured in the pool (usually its 0.1%)
One interesting thing to observe here is that these pools are self rebalancing in the way that once pools gets imbalanced by one sided transfer, protocol starts creating incentives for the users to balance out the pool by doing the cross chain transfer in opposite direction of the demand. This incentive comes from the high fee charged from the user when they are trying to take funds from a pool where available liquidity is less than supplied liquidity.
More detailed information can be found here Self-Balancing-Cross-Chain-Liquidity-Pools
You can check out the Hyphe UI here on test networks https://hyphen-staging.biconomy.io
|Liquidity Pool||Liquidity pool contract where LPs will provider liquidity. Single contract deployed on each supported chain, contains multiple tokens liquidity including native token|
|Executors||Off chain accounts that is run by Biconomy who have access to Liquidity present in Liquidity Pools on each chain|
|Deposit Transaction||Transaction done by the user on source chain who want to move his funds from source chain to destination chain|
|Transfer Transaction||Transaction done by the Executors on destination chain where user gets his funds from the Liquidity Pool after deducting transfer fee|
|Cross Chain Transfer||Deposit Transaction + Transfer Transaction makes one cross chain transfer|
|LPToken||ERC721 Token that represents share in Liquidity Pool|
|Supplied Liquidity (SL)||Total liquidity supplied by Liquidity Providers in the pool|
|Available Liquidity (AL)||Current available liquidity available in the pool for cross chain transfers|
|Equilibrium State||State of the liquidity pool when supplied liquidity = available liquidity|
|Deficit State||State of the liquidity pool when supplied liquidity > available liquidity|
|Excess State||State of the liquidity pool when supplied liquidity < available liquidity|
|Incentive Pool||Mapping stored in Liquidity Pool that contains incentive amount that is given to user deposit when pool is in deficit state|
|Equilibrium Fee||Percentage fee deducted from user transfer amount that is distributed to LPs when funds are given from Liquidity Pool|
|Dynamic Transfer Fee||Equilibrium Fee + Incentive Pool Fee, This is dynamic number calculated based on SL and AL|
|Gas Fee||Fee deducted from user transfer amount in the token being transferred that is equal to gas being used in transfer transaction|
|Total Transfer Fee||Dynamic Transfer Fee + Gas Fee|
All the contracts in this section are to be reviewed. Any contracts not in this list are to be ignored for this contest.
ExecutorManager.sol (41 sloc each)
Contract containing all Executor addresses that are authorised to call sendFundsToUser method of LiquidityPool.sol. Only owner of this contract can add or remove executor addresses. onlyExecutor modifier is used wherever we want to restrict the method access to only Executors.
- External contracts called: None
- Libraries used: None
TokenManager.sol (111 sloc each)
Contract containing supported tokens and their configurations mentioned below. Only Owner of this contract can add/remove tokens and modify their configurations.
-- Transfer Config
- transferOverhead: Pre estimated gas used in transfer transaction that can't be dynamically estimated on contract.
- supportedToken: Boolean value that tells if this token is supported or not
- equilibriumFee: Percentage transfer fee to be used when pool is in equilibrium position
- maxFee: Percentage transfer fee when cross chain transfer use up all the liquidity present in the pool
- min: Min amount of tokens that can be transferred from the pool in single transaction.
- max: Max amount of tokens that can be transferred from the pool in single transaction.
-- Deposit Config
- min: Min amount of tokens that can be deposited in the pool in single transaction.
- max: Max amount of tokens that can be deposited in the pool in single transaction.
External contracts called: None
Libraries used: None
LiquidityPool.sol (351 sloc each)
Contract that holds all the liquidity for all supported tokens. This contract provide methods to deposit funds in the pool on source chain and transfer funds from the pool on destination chain.
- depositErc20: Method to deposit supported ERC20 tokens
- depositNative: Method to deposit supported native token of current network. Eg. ETH on Ethereum, MATIC on Polygon
- sendFundsToUser: Method to be called by Executors to transfer funds from the pool on destination chain to the user. It handles both Native and ERC20 tokens.
External contracts called:
- All supported ERC20 tokens.
Libraries used: None
LiquidityProviders.sol (304 sloc each)
Contract that provides methods to Liquidity Providers to add/remove/increase liquidity and claim rewards.
- addTokenLiquidity: Method to add ERC20 token liquidity
- addNativeLiquidity: Method to add Native token liquidity
- increaseTokenLiquidity: Method to increase the ERC20 liquidity in given position denoted by NFT ID
- increaseNativeLiquidity: Method to increase the Native token liquidity in given position denoted by NFT ID
- removeLiquidity: Method to remove liquidity from given position.
- claimFee: Method to claim the accumulated fee for given position.
External contracts called
- All supported ERC20 tokens.
Libraries used: None
WhitelistPeriodManager.sol (240 sloc each)
This contract enforces limits on the total and per wallet supplied liquidity for a given token. The contract exposes the following functions: a. beforeLiquidityAddition(), beforeLiquidityRemoval(), which are called by the LiquidityProvider contract before liquidity is added or removed. b. beforeLiquidityTransfer() which is called bt the LPToken before positions are transferred. The functions verify if all limits are being respected, and reverts in case a limit is being crossed. External Contracts Called: - LiquidityProviders - TokenManager
LPToken.sol (201 sloc each)
An ERC721 Token, signifies liquidity provided by an LP for a given token pool. Whenever an LP supplied liquidity for a given token, an NFT is minted to them. Whoever owns the NFT has the rights to claim the liquidity and any associated rewards from the pool. External Contracts Called: - SvgHelpers - Whitelist Period Manager - LiquidityProviders
HyphenLiquidityFarming.sol (373 sloc each)
Liquidity Providers can optionally lock their LP Tokens (NFTs) in this contract to earn rewards in BICO Tokens External Contracts Called: - LiquidityProviders - LPToken
Additional protocol information
When liquidity providers provide liquidity they are provided with LP Token which in this case is ERC721 token. Each time you add liquidity in the pool you get a new LP Token that represents your new position. If you want to increase the liquidity in your existing position, you should call increaseLiquidity method in LiquidityProviders.sol instead of addLiquidity methods.
Farming contracts are also deployed to run liquidity incentive programs where LPs can stake their LP Token in farming contract and earn more rewards. These rewards are given in ERC20 or native token on that chain and are configured to be given per second for certain duration of time. Rewards are distributed on the basis of how much liquidity LPs have provided that is represented by their NFT (LP Token)
User interaction starts on source chain when user deposit his funds in liquidity pool on the source chain. Once the transaction is confirmed user interaction is no longer needed and user just needs to wait for transfer transaction done by Executors.
There may be a scenario when some pools in all supported chains are in deficit state and some pools are in excess state. So when a user deposit funds in deficit state and go to a chain where pool is in excess state, the incentives on source chain can be more than the transfer fee on destination chain. This is the arbitrage opportunity where user gets more funds on destination chain than what he deposited on source chain.
These incentives drive users to balance the pool themselves. People can run bots on hyphen pool that constantly look out for this opportunity for balancing the pool and take the incentives for doing so.
Potential Protocol concerns
Make sure the dynamic fee formulae works properly and the incentives are enough for the protocol to balance the pools without incurring high transfer fee to users.
Areas of concern for Wardens
Make sure the logic is correct around liquidity fee distribution and dynamic fee calculated. Also make sure the rewards calculation in Farming contracts works properly as more LPs stake their LP Token in farming contract to get more rewards.
A full set of unit tests are provided in the repo. To run these do the following:
Prepare local enviroment
nodejs, refer to nodejs.
yarn, refer to yarn.
yarnto install all dependencies.
yarn testto run the tests.
The following token contracts are used by the protocol on Goerli:
The following token contracts are used by the protocol on Mumbai:
The following token contracts are used by the protocol on Fuji:
Following are the contracts deployed on Goerli:
Following are the contracts deployed on Mumbai:
Following are the contracts deployed on Fuji: