Bracket Labs

Channel Smart Contracts

Please see our AUDIT for security review
Below we describe our smart contracts and functions. We are currently using:
  • Solidity version 0.8.12
  • OpenZeppelin version 4.7.3
We have implemented the OpenZeppelin upgradeable contract pattern and will be using a multi-sig Gnosis wallet in production in conjunction with the OpenZeppelin Defender deployment and administration platform
We use many OpenZeppelin contracts, including:
  • AddressUpgradeable
  • CountersUpgradeable
  • StringsUpgadable
  • MathUpgradeable
  • SafeMathUpgradeable
  • OwnableUpgradeable
  • PausableUpgradeable
  • ReentrancyGuardUpgradeable
  • Initializable
  • ERC20
  • ERC721Upgradeable / ERC721EnumerableUpgradeable
Important implementation details:
  • Contract Structure Versions:
    • Bracket Labs controls the version of the Contract Structure in terms of the 8 potential offers "slots", our UI is currently only using 3 of the 8
    • We associate a version with the Funder's offers to ensure we only show current offers, and ensure the offers match the current Contract Structure
    • We associate the Contract Structure version with policies to ensure we use the correct information when processing the policy, even if that version no longer matches the current Contract Structure version
  • Assets are defined by their Chainlink proxy addresses, which is different in Test than Production
  • We implement the best-practice of using the Solidity Withdrawal Pattern where funds are not instantly disbursed but put into a withdrawable state and then a second function call must execute the withdrawal. A brief explanation why this is preferable can be found here:
The Channel specific contracts mirror the structure of the Bracket contracts:
  • ChanLib - This is a non-data library function where many of the data structures used are defined
  • ChanConfig - this has almost no logic is just stores configuration information and data which includes:
    • The CVers data stores the Contract Structure version information
    • The key functions are:
      • currentVer - returns the Contract Structure version being used
      • getVer - returns the Contract Structure information for a given version number
      • addVer - [OWNER ONLY] - add a new Contract Structure version that becomes current
      • Functions to modify the various contract constants such as:
        • Minimum / Maximum available (that can be added)
        • Minimum premium (buy amount)
        • The two commission percentages for Buys (premium) and when a claim is made
      • setETH is used to set the official ETH asset address so the contract can know the USD value of the ETH sent
  • CNFT is an extension of the OpenZeppelin ERC721 NFT contract, and stores the contract information. When a contract is purchased an NFT is issued that becomes the contract number. The owner of this NFT is the owner of the contract with all privileges granted. In addition to the standard NFT functionality of transferring ownership, we added the functions:
    • onlyChan (modifier) / setChannel - many functions can ONLY be performed by the Channel contract. Most important of them is the MINT function
    • mintCNFT - [CHAN ONLY] this creates a new NFT which can ONLY be minted by the BUY function of the Channel contract. The metadata used for the image shown is dynamically set based on either NFT number, time, or another data element passed in
    • setPolicy - [CHAN ONLY] this associates policy information with an NFT, which can ONLY be called by the BUY function of the Channel contract
    • setClaimed - [CHAN ONLY] this updates the status of a Policy to be considered claimed. This is important so the Policy is not double paid. This can ONLY be called by the CLAIM function of Channel contract
  • Pricing is where the Chainlink oracle pricing is managed. Channel shares the same Pricing contract as BracketX. If on Arbitrum we check if the L2's sequencer is running, so we don't return stale prices.
    • getLatestPrice - returns the Chainlink price as returned by their latestRoundData function
    • getClaimPrice - for production, it returns getClaimPrice
    • addDepeg [Owner ONLY]- set an asset as a de-peg asset
    • remDepeg [Owner ONLY] - set an asset to NOT being a de-peg asset
    • setGracePeriod - this grace period used to determine if L2's sequencer is still running
    • setClaimDelta - for TESTING ONLY to simulate market conditions where the contract is in-the-money. This is not implemented in production
    • For de-pegging assets we limit price to 1.0
    • For stETH, we return stETH / ETH as the price of stETH
  • ChanOffers - this contract stores the Funder's Offers. The key functions are:
    • getOffer - return an offer for a Funder for a given asset
    • setOffer [Funder ONLY]- this sets the current offer. The frontend sends what it believes is the current version and if it doesn't match the contract's current Contract Structure version, the offer is rejected. A Funder is not able to update an old offer as they are instantly expired once a new Contract Structure version is issued
  • Channel - this is the key contract where the majority of the logic is stored. As such, it is the last contract initialized since it must know the address of all the other contracts
    • The data stored by this contract includes:
      • FunderAvail - the available amount in USDC of Funders, which is available, but not yet committed to a Policy. These funds can take out at any time by the funder but reducing their Available and moving the funds into a withdrawable state
      • pendingETHwithdrawals - the amount of ETH available to be withdrawn by an address holder, which could be a funder or buyer
      • pendingUSDCwithdrawals - the amount of USDC available to be withdrawn by an address holder, which could be a funder or buyer
    • The key functions include:
      • getWithdrawableAmts - returns the amount of ETH and USDC available for immediate withdrawal
      • addAvailable [Funder ONLY] - allows a funder to add USDC to their available amount
      • reduceAvailable [Funder ONLY] - allows a funder to remove their USDC from being available. The reduced USDC funds move into a withdrawable state
      • buyPolicy [payable function] - this is how a policy is bought from an offer. The funder and offerId must be given, so this is a 1:1 match. The algorithm of determining which offer gets executed is down in the frontend, so this function just executes that match. It is a payable function as it takes native coin for policy payment. Notice the version number is checked. A max and min asset price is sent to check for slippage. If the price moved out of bounds between the time the user committed on the front end until it executed on the blockchain, then the transaction is reverted. This function calls the CNFT contract to issue an NFT as the policy id. Notice two Buy Events are emitted by this function. This is because buy Events are limited to only 10 variables
      • claim - this is called to make a claim. A claim can be by anyone since there is no way to claim early. Claims can ONLY be made after the asset's price has broken out of the price channel, or after expiration. Claims are made automatically by BracketX's automation system. The claim function sets the policy's state to claimed and moves the buyers claim amount in USDC to a withdrawable state. For Funders, any unclaimed USDC moves back to being Available. Any commissions are moved into Bracket Labs's commission account
      • withdraw - this disburses any USDC's or ETH's funds in the callers withdrawable state into their the callers wallet
  • FakeUSDC - This is a TESTING ONLY contract we use as a substitute for the real USDC contract. This contract will NOT be used in production