Skip to content

Halo Finance is a fork of Compound that creates isolated lending markets where only registered agents (per ERC-8004: Trustless Agents) can borrow.

License

Notifications You must be signed in to change notification settings

TreasureProject/Halo-Finance

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

524 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Halo Finance Market Protocol Documentation

Halo Finance is a fork of Compound V3 that creates isolated lending markets where only registered agents (per ERC-8004: Trustless Agents) can borrow.

Overview

Halo Finance V1 is a decentralized, monolithic, efficient money market protocol forked from Compound V3, featuring a single-collateral lending system with a unique agent reputation scoring mechanism. The protocol enables users to supply base assets (typically stablecoins) and borrow against collateral assets (like MAGIC), with built-in mechanisms like liquidation, reward distribution, protocol fee, discount on fee based on agent's reputation score etc.

The Halo v1 deployment will launch with a single MAGIC ⇄ USD market on Abstract. This deliverable includes two components: the Compound fork and a light adjustment to ERC-8004 registries for our use case.

Usage Flow

  1. Supplying Assets:
// Supply base token
comet.supply(baseToken, amount);

// Supply collateral
comet.supply(collateralAsset, collateralAmount);
  1. Agent Registration
agentId = agentRegistry.registerFor(to, tokenUri);
  1. Borrowing
// First supply collateral
comet.supply(collateralAsset, collateralAmount);

// Then borrow base token
comet.withdraw(baseToken, borrowAmount, agentId);
  1. Repaying Debt
// Repay full debt
comet.supply(baseToken, type(uint256).max);

// Repay specific amount
comet.supply(baseToken, repayAmount);
  1. Liquidating Position
// liquidate borrower's position
comet.absorb(liquidator, accounts);
  1. Withdrawing base token with rewards
comet.withdraw(baseToken, withdrawAmount, 0);
  1. Withdrawing collateral
comet.withdraw(collateralAsset, collateralAmount, 0);
  1. Checking Borrow Position's Health
// Check if position is healthy
bool healthy = comet.isBorrowCollateralized(agentAddress);

// Check if position can be liquidated
bool liquidatable = comet.isLiquidatable(agentAddress);
  1. Checking agent's total debt(initial borrow balance + interest).
uint totalDebt = comet.borrowBalanceOf(agentAddress);
  1. Checking agent's total debt to pay(initial borrow balance + interest + protocolFee - discount).
uint totalDebtToPay = comet.debtAfterProtocolFeeAndDiscount(agentAddress);
  1. Checking agent's total base token supply(initial supply + rewards)
comet.balanceOf(agentAddress);

Architecture

Key Features

  1. Agent Reputation System
  • 0 - 1 scoring based reputation system to incentivise good actors.
  • Tracks agents behavior and provides fee discounts based on reputation.
  • Agents with good reputation scores get discounts(up-to 100%) on protocol fees.
  • Dynamic scoring based on utilization rates and position size.
  • Rewards long-term, responsible market participants.
  1. Single-Collateral Market
  • Supports only one base token (e.g., USDC) to lend/borrow.
  • Supports only one collateral token (e.g., MAGIC) to borrow against.
  • Simplified risk management compared to multi-collateral systems.
  1. Protocol Fees with Discounts
  • Charged on borrowing activities.
  • Discounts applied based on reputation score.
  • Fees accrue to protocol reserves.
  1. Interest Rate Model
  • Kinked interest rate curves for both supply and borrow.
  • Utilization-based rates that increase above optimal thresholds.
  • Separate parameters for lenders(e.g. supplyKink) and borrowers(e.g. borrowKink).

Core Contracts

  • Comet - Main Money Market Contract.
  • CometFactory - Money Market Deployment Factory Contract.
  • IdentityRegistry - Identity registry contract to register borrowing agents.

Core Components

Configuration:

struct Configuration {
    address governor;           // Multi-sig governance
    address pauseGuardian;      // Emergency pauser
    address identityRegistry;   // Agent registry
    address baseToken;          // Borrowable asset (e.g., USDC)
    address baseTokenPriceFeed; // Price oracle
    address extensionDelegate;  // Upgrade delegate
    
    // Interest Rate Parameters
    uint64 supplyKink;
    uint64 supplyPerYearInterestRateSlopeLow;
    uint64 supplyPerYearInterestRateSlopeHigh;
    uint64 supplyPerYearInterestRateBase;
    
    uint64 borrowKink;
    uint64 borrowPerYearInterestRateSlopeLow;
    uint64 borrowPerYearInterestRateSlopeHigh;
    uint64 borrowPerYearInterestRateBase;
    
    // Collateral Parameters
    uint64 storeFrontPriceFactor;
    
    // Reward Parameters
    uint64 trackingIndexScale;
    uint64 baseTrackingSupplySpeed;
    uint64 baseTrackingBorrowSpeed;
    uint104 baseMinForRewards;
    
    // Fee Configuration
    uint64 protocolFee;
    uint64 maxDiscount;
    address protocolFeeRecipient;
    
    // Risk Parameters
    uint104 baseBorrowMin;
    uint104 targetReserves;
    
    // Collateral Configuration
    CollateralConfig collateralConfig;
}

Agent Positions:

struct AgentBasic {
    int104 principal;           // Net base position (+supplied, -borrowed)
    uint64 baseTrackingIndex;   // Reward snapshot index
    uint64 baseTrackingAccrued; // Unclaimed rewards
    uint8 _reserved;
}

// Single base token balance(+supplied, -borrowed) per agent and other basic data
mapping(address => AgentBasic) public agentBasic;

// Single collateral balance per agent
mapping(address => uint128) public agentCollateralSupply;

Reputation System:

struct AgentRepScore {
    uint score;                 // Accumulated reputation points
    uint scoreMultiplier;       // Current multiplier (based on utilization)
    uint baseSupplyOrBorrowRatio; // Position size relative to expected maximum
    uint lastScoreUpdatedAt;    // Last update timestamp
}

// Tracking agent's reputation score based on their lending/borrowing activities.
mapping(address => AgentRepScore) internal agentsReputationScores;

Key Mechanisms

  1. Supply & Borrow
  • Base Asset Operations:
    • Supply: Deposit base token to earn interest.
    • Borrow: Take out loans against collateral.
    • Withdraw: Remove base token from supply.
  • Collateral Operations:
    • Supply Collateral: Deposit collateral to enable borrowing.
    • Withdraw Collateral: Remove collateral (if position remains healthy).
  1. Interest/Rewards Accrual
  • Base Indices:
    • baseSupplyIndex: Tracks accumulated interest for suppliers.
    • baseBorrowIndex: Tracks accumulated interest for borrowers.
    • Updates continuously based on utilization rate.
  • Reward Indices:
    • trackingSupplyIndex: Tracks reward distribution for suppliers.
    • trackingBorrowIndex: Tracks reward distribution for borrowers.
    • Updates based on reward speeds and eligible balances.
  1. Interest Rate Models
  • Supply Rates:
if utilization ≤ supplyKink:
    rate = supplyPerSecondInterestRateBase + 
           (supplyPerSecondInterestRateSlopeLow × utilization)
else:
    rate = supplyPerSecondInterestRateBase + 
           (supplyPerSecondInterestRateSlopeLow × supplyKink) +
           (supplyPerSecondInterestRateSlopeHigh × (utilization - supplyKink))
  • Borrow Rates:
if utilization ≤ borrowKink:
    rate = borrowPerSecondInterestRateBase + 
           (borrowPerSecondInterestRateSlopeLow × utilization)
else:
    rate = borrowPerSecondInterestRateBase + 
           (borrowPerSecondInterestRateSlopeLow × borrowKink) +
           (borrowPerSecondInterestRateSlopeHigh × (utilization - borrowKink))
  1. Reputation Scoring
  • Score Calculation:
repScore = (baseSupplyOrBorrowRatio × scoreMultiplier × elapsedTime) / SECONDS_PER_YEAR;
  • Multiplier Logic:
    • For Lenders: Increases with utilization up to kink, then accelerates.
    • For Borrowers: Increases with utilization up to kink, then accelerates.
    • Scoring: up-to 1x multiplier at optimal utilization, up-to 2x at 100%, up-to 3x at 100%.
  1. Protocol Fees
  • Fee Calculation:
totalFee = (debt × protocolFeeInPct) / FACTOR_SCALE;
discount = (totalFee × reputationScore × maxDiscountInPct) / FACTOR_SCALE²;
finalFee = totalFee - discount;
  1. Liquidations
  • Conditions for Liquidation:
    • Agent's borrow position exceeds liquidation collateral factor.
    • Protocol absorbs underwater positions.
    • Liquidators can buy collateral at a discount.
  • Absorption Process:
    • Protocol takes over agent's collateral.
    • Debt is added to protocol reserves.
    • Liquidators earn points for participating.

Important Functions

  • Protocol Management:
    • pause() - Pause specific operations
    • withdrawReserves() - Withdraw protocol reserves (governor only)
    • approveThis() - Grant token approvals (governor only)
    • updateProtocolFeeRecipient() - Updates the address that receives protocol fees (governor only).
    • collectProtocolFee() - Transfers accumulated protocol fees to the fee recipient (governor only).
  • Agent Operations:
    • supply() / supplyTo() / supplyFrom() - Supply/Repay assets
    • withdraw() / withdrawTo() / withdrawFrom() - Withdraw/Borrow assets
    • approve() / allow() / allowBySig() - Allow/disallow a spender to withdraw, or transfer on sender's behalf.
    • transfer() / transferFrom() - Transfer base token
    • transferAsset() / transferAssetFrom() - Transfer collateral
    • accrueAccount() - Accrue interest and rewards for an agent
    • accrueAgentRepScore() - Accrue reputation score for an agent
  • Liquidation:
    • absorb() - Liquidate underwater accounts
    • buyCollateral() - Purchase collateral from protocol
  • Queries (Read-Only)
    • totalSupply() - Get the total number of base tokens in circulation.
    • totalBorrow() - Get the total amount of debt.
    • balanceOf() - Get agent's inital base token supply + accruedInterest
    • borrowBalanceOf() - Get agent's inital borrow balance + accruedInterest
    • debtAfterProtocolFeeAndDiscount(address _agent) - Query agent's total repay amount of base token including protocol fee after reputation-based discount, if debt is positive (0 if negative).
    • debtAfterProtocolFeeAndDiscount(uint _debt, address _agent) - Query agent's partial repay amount of base token for a specific debt amount including protocol fee after reputation-based discount.
    • calculateRepScoreMultiplier() - Calculates agent reputation score multiplier at current utilization rate.
    • getAgentReputationScore() - Get agent's accrued reputation score.
    • getAgentReputationConfig() - Get agent's current reputation score config.
    • getUtilization() - Get base token current market utilization.
    • getSupplyRate() - Get the per second supply rate at current utilization.
    • getBorrowRate() - Get the per second borrow rate at current utilization.
    • isBorrowCollateralized() - Check whether an agent has enough collateral to borrow.
    • isLiquidatable() - Check whether an agent's position is undercollateralized and can be liquidated.
    • baseTrackingAccrued() - Query the total accrued base rewards for an agent.
    • getAccruedInterestIndices() - Get accrued interest indices for base token supply and borrows.
    • getReserves() - Calculates the total amount of protocol reserves of the base token.
    • getCollateralReserves() - Gets the total balance of protocol collateral reserve for a collateral.
    • collateralBalanceOf() - Query the current collateral balance of an agent.
    • getCollateralInfo() - Get complete collateral configuration information.
    • totalsBasic() - Aggregate variables tracked for the entire market.
    • getPrice() - Get the current price from a feed.
    • quoteCollateral() - Get the quote for the collateral asset in exchange for an amount of base asset.
    • allowance() - Get the current allowance from owner for spender

Function Details

State Mutating Functions (Public):

pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused)

  • Description: Pauses/unpauses specific protocol functions for emergency control.
  • Permission: Governor or Pause Guardian only
  • Parameters:
    • Boolean flags for each function type to pause/unpause
  • Emits: PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused)
  • Returns: None

withdrawReserves(address to, uint amount)

  • Description: Withdraws base token reserves from the protocol.
  • Permission: Governor only
  • Parameters:
    • to: an address of the receiver of withdrawn reserves.
    • amount: the amount of reserves to be withdrawn from the protocol.
  • Requirements:
    • Reserves must be sufficient
    • Amount must be ≤ available reserves
  • Emits: WithdrawReserves(address indexed to, uint amount)
  • Returns: None

approveThis(address manager, address asset, uint amount)

  • Description: Sets ERC20 allowance for a manager to handle protocol assets.
  • Permission: Governor only
  • Parameters:
    • asset: The asset that the manager will gain approval of
    • manager: The account which will be allowed or disallowed
    • amount: The amount of an asset to approve
  • Requirements: For USDT, if there is non-zero prior allowance, it must be reset to 0 first before setting a new value in proposal.
  • Returns: None

updateProtocolFeeRecipient(address _newRecipient)

  • Description: Updates the address that receives protocol fees.
  • Permission: Governor only
  • Parameters:
    • _newRecipient: New fee recipient address
  • Requirements: New recipient cannot be zero address
  • Emits: ProtocolFeeRecipientUpdated(address oldRecipient, address newRecipient)
  • Returns: None

collectProtocolFee()

  • Description: Transfers accumulated protocol fees to the fee recipient address.
  • Permission: Governor only
  • Requirements: Accumulated protocol fee must be > 0
  • Emits: ProtocolFeeCollected(uint amount)
  • Returns: None

initializeStorage()

  • Description: Initializes storage variables, can be called from constructor or proxy.
  • Permission: Anyone
  • Requirements: Storage must not already be initialized.
  • Returns: None

supply(address asset, uint amount)

  • Description: Supply/Repay assets (base token or collateral asset) to the protocol.
  • Permission: Anyone
  • Parameters:
    • asset: Token address (base token or collateral)
    • amount: Amount to supply/repay (uint256.max to repay all debt)
  • Requirements:
    • Supply not paused
    • Must be base token or collateral asset
    • pass type(uint256).max to repay all debt
  • Emits:
    • Supply(address indexed from, address indexed dst, uint amount)
    • Transfer(address indexed from, address indexed to, uint amount) (if base token supplied)
    • SupplyCollateral(address indexed from, address indexed dst, uint amount) (if collateral supplied)
  • Returns: None

supplyTo(address dst, address asset, uint amount)

  • Description: Supply/Repay assets (base token or collateral asset) to a specific address dst.
  • Permission: Anyone
  • Parameters:
    • dst: The address which will hold the balance
    • Other parameters same as supply().
  • Requirements: Same as supply().
  • Emits: events same as supply().
  • Returns: None

supplyFrom(address from, address dst, address asset, uint amount)

  • Description: Supply/Repay assets (base token or collateral asset) from from to dst (with permission).
  • Permission: Operator permission.
  • Parameters:
    • from: The address from which the asset will be transferred
    • dst: The address which will hold the balance
    • Other parameters same as supply().
  • Requirements:
    • Operator must have permission from from.
    • Other requirements same as supply().
  • Emits: events same as supply().
  • Returns: None

withdraw(address asset, uint amount, uint agentId)

  • Description: Withdraw/Borrow assets (base token or collateral asset) from the protocol.
  • Permission: Anyone can withdraw their liquidity, only registered agents can borrow.
  • Parameters:
    • asset: The asset to withdraw
    • amount: Amount to withdraw (uint256.max for all)
    • agentId: Registered agent ID for borrowing
  • Requirements:
    • Withdraw not paused
    • Must be base token or collateral asset
    • pass type(uint256).max to withdraw all accrued base balance
    • For borrowing: agent must be registered, borrow ≥ minimum, account must be collateralized
  • Emits:
    • Withdraw(address indexed src, address indexed to, uint amount)
    • WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount) (if collateral withdrawn)
    • Transfer(address indexed from, address indexed to, uint amount) (if base token withdrawn)
  • Returns: None

withdrawTo(address to, address asset, uint amount, uint agentId)

  • Description: Withdraw/Borrow assets (base token or collateral asset ) to a specific address.
  • Permission: Same as withdraw().
  • Parameters:
    • to: The recipient address
    • Other parameters same as withdraw().
  • Requirements: Same as withdraw().
  • Emits: events same as withdraw().
  • Returns: None

withdrawFrom(address src, address to, address asset, uint amount, uint agentId)

  • Description: Withdraw/Borrow assets (base token or collateral asset) from src to to (with permission).
  • Permission: Operator permission.
  • Parameters:
    • src: The source address
    • to: The recipient address
    • Other parameters same as withdraw().
  • Requirements:
    • Operator must have permission from the src.
    • Other requirements same as withdraw().
  • Emits: events same as withdraw().
  • Returns: None

accrueAccount(address _agent)

  • Description: Accrue interest and rewards for an agent.
  • Permission: Anyone
  • Parameters:
    • _agent: Agent address whose interest and rewards is being accrued
  • Returns: None

accrueAgentRepScore(address _agent)

  • Description: Accrue reputation score for an agent.
  • Permission: Anyone
  • Parameters:
    • _agent: Agent address whose reputation score is being accrued
  • Returns: None

approve(address spender, uint256 amount) → (bool)

  • Description: ERC20-compatible approve function with binary allowance model. Approve or disallow spender to transfer on sender's behalf.
  • Permission: Caller must be the token owner (msg.sender is owner)
  • Parameters:
    • spender: The address to grant/revoke permission
    • amount: Either type(uint256).max (to allow) or 0 (to disallow)
  • notice:
    • this binary approval is unlike most other ERC20 tokens
    • this grants full approval for spender to manage all the owner's assets
    • amount == type(uint256).max: Grants full permission
    • amount == 0: Revokes all permission
    • Any other amount: Reverts with BadAmount()
  • Emits: Approval(address indexed owner, address indexed spender, uint256 amount)
  • Returns: Whether or not the approval change succeeded

allow(address manager, bool isAllowed_)

  • Description: Allow or disallow another address to withdraw, or transfer from the sender.
  • Permission: Caller must be the token owner (msg.sender is owner)
  • Parameters: Anyone can call with a valid signature.
    • manager: The address to grant/revoke permission
    • isAllowed_: Whether to allow or disallow. true to allow, false to disallow
  • notice: Consider using approve() for ERC20 compatibility
  • Emits: Approval(address indexed owner, address indexed spender, uint256 amount)
  • Returns: None

allowBySig(address owner, address manager, bool isAllowed_, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)

  • Description: Sets authorization status via EIP-712 signature (meta-transaction) for a manager from a signatory.
  • Permission: Anyone can call with a valid signature.
  • Parameters:
    • owner: The address that signed the signature
    • manager: The address to authorize (or rescind authorization from)
    • isAllowed_: Whether to authorize or rescind authorization from manager
    • nonce: The next expected nonce value for the signatory
    • expiry: Expiration time for the signature
    • v: The recovery byte(27 or 28) of the signature
    • r: Half of the ECDSA signature pair
    • s Half of the ECDSA signature pair
  • Requirements:
    • Checks s < MAX_VALID_ECDSA_S
    • Checks v == 27 || v == 28
    • Checks signatory != address(0)
    • Verifies owner == signatory
    • Checks nonce == userNonce[signatory]
    • Checks block.timestamp < expiry
  • Emits: Approval(address indexed owner, address indexed spender, uint256 amount)
  • Returns: None

transfer(address dst, uint amount) → (bool)

  • Description: ERC20-like transfer of base token.
  • Permission: Anyone
  • Parameters:
    • dst: The recipient address
    • amount: The amount to transfer
  • Requirements:
    • Transfer not paused
    • Source ≠ destination
    • pass type(uint256).max to transfer all accrued base balance
    • If creating debt: borrow ≥ minimum, account must be collateralized
  • Emits: Transfer(address indexed from, address indexed to, uint amount)
  • Returns: true

transferFrom(address src, address dst, uint amount) → (bool)

  • Description: ERC20-like transfer of base token from src to dst (with permission).
  • Permission: Operator permission.
  • Parameters:
    • src: The source address
    • Other parameters same as transfer().
  • Requirements:
    • Operator must have permission from src.
    • Other requirements same as transfer().
  • Emits: Transfer(address indexed from, address indexed to, uint amount)
  • Returns: true

transferAsset(address dst, address asset, uint amount)

  • Description: ERC20-like transfer of collateral asset.
  • Permission: Anyone
  • Parameters:
    • dst: The recipient address
    • asset: The collateral asset to transfer
    • amount: The amount to transfer
  • Requirements:
    • Transfer not paused
    • Must be collateral asset
    • Source account must remain collateralized
  • Emits: TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount)
  • Returns: None

transferAssetFrom(address src, address dst, address asset, uint amount)

  • Description: ERC20-like transfer of collateral asset from src to dst (with permission).
  • Permission: Operator permission.
  • Parameters:
    • src The source address
    • Other parameters same as transferAsset().
  • Requirements:
    • Operator must have permission from src.
    • Other requirements same as transferAsset().
  • Emits: TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount)
  • Returns: None

buyCollateral(uint minAmount, uint baseAmount, address recipient)

  • Description: Purchase collateral from protocol at a discount during liquidation using base tokens, increasing protocol reserves.
  • Permission: Anyone
  • Parameters:
    • minAmount: The minimum amount of collateral tokens that should be received by the buyer (slippage protection)
    • baseAmount: The amount of base tokens used to buy the collateral
    • recipient: The collateral recipient address
  • Requirements:
    • Buy not paused
    • Reserves must be below targetReserves
    • Collateral amount ≥ minAmount (slippage protection)
    • Sufficient collateral reserves
  • Emits: BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount)
  • Returns: None

absorb(address absorber, address[] calldata accounts)

  • Description: Absorb a list of underwater accounts onto the protocol balance sheet, transferring collateral/debt to protocol.
  • Permission:
  • Parameters:
    • absorber: The liquidator address (receives incentives)
    • accounts: The list of underwater accounts to absorb
  • Requirements:
    • Absorb not paused
    • Each account must be liquidatable
  • Emits:
    • AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue)
    • AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue)
    • Transfer(address indexed from, address indexed to, uint amount) (if principal remains)
  • Returns: None

CometFactory::deployNewMarket(Configuration calldata _config) → (address market)

  • Permission: Factory owner only (anyone if contract ownership is renounced).
  • Description: Deploys a new Comet money market instance.
  • Parameters:
    • config: Complete market configuration
  • Emits: NewMarketCreated(address base, address collateral, address market)
  • Returns: Address of newly deployed Comet contract.

Read-Only Functions (Public)

totalSupply() → (uint)

  • Description: Get the total number of base tokens in circulation.
  • Notice:
    • uses updated interest indices to calculate total protocol supply
    • totalProtocolSupply = totalSupplyBase + accruedInterest;
  • Returns: Total base tokens supplied to protocol (with accrued interest)

totalBorrow() → (uint)

  • Description: Get the total amount of debt.
  • Notice:
    • uses updated interest indices to calculate total protocol debt
    • totalProtocolBorrow = totalBorrowBase + accruedInterest;
  • Returns: Total base tokens borrowed from protocol (with accrued interest)

balanceOf(address _agent) → (uint)

  • Description: Query the current positive base balance of an agent(i.e. total base token supplied by agent), 0 if negative.
  • Parameters:
    • _agent: The agent whose base balance to query
  • Notice:
    • uses updated interest indices to calculate total agent supply
    • totalAgentSupply = totalPrincipalSupplied + accruedInterest;
  • Returns: The present day base balance magnitude of the agent, if positive (0 if negative).

borrowBalanceOf(address _agent) → (uint)

  • Description: Query the current negative base balance of an agent(i.e. total base token borrowed by agent), 0 if positive.
  • Parameters:
    • _agent: The agent whose base balance to query
  • Notice:
    • uses updated interest indices to calculate total agent debt
    • totalAgentBorrow = totalPrincipalBorrowed + accruedInterest;
  • Returns: The present day base balance magnitude of the agent, if negative (0 if positive).

debtAfterProtocolFeeAndDiscount(address _agent) → (uint)

  • Description: Query agent's total repay amount of base token including protocol fee after reputation-based discount, if debt is positive (0 if negative).
  • Parameters:
    • _agent: The agent whose repay debt balance to query
  • Notice:
    • uses updated interest indices to calculate total agent debt
    • includes protocol fee to calculate total debt repay amount
    • applies discount based on agent's reputation score to reduce total debt repay amount
    • totalAgentDebtToRepay = totalPrincipalBorrowed + accruedInterest + protocolFee - discount;
  • Returns: The present day base balance magnitude of the agent + protocol fee - discount, if debt is positive (0 if negative).

debtAfterProtocolFeeAndDiscount(uint _debt, address _agent) → (uint)

  • Description: Query agent's partial repay amount of base token for a specific debt amount including protocol fee after reputation-based discount.
  • Parameters:
    • _debt: A specific debt amount which will be used to calculate total repay amount
    • _agent: The agent whose repay amount to query
  • Notice:
    • assumes agent's _debt was already calculated using updated interest indices
    • includes protocol fee to calculate total repay amount
    • applies discount based on agent's reputation score to reduce total repay amount
    • totalAgentDebtToRepay = debtWithAccruedInterest + protocolFee - discount;
  • Returns: The present day base balance magnitude of the agent + protocol fee - discount.

calculateRepScoreMultiplier(bool _isLender) → (uint scoreMultiplier)

  • Description: Calculates agent reputation score multiplier based on utilization current utilization rate and position type.
  • Parameters:
    • _isLender: Whether the agent is a lender or a borrower.
  • Notice:
    • scoreMultiplier is 1x when utilization rate is 0
    • scoreMultiplier is up-to 1x when utilization rate <= optimal utilization rate
    • scoreMultiplier is up-to 3x when utilization rate > optimal utilization rate
  • Returns: Agent's reputation score multiplier based on utilization current utilization rate and position type.

getAgentReputationScore(address _agent) → (uint score, uint scoreLastUpdatedAt)

  • Description: Get agent's accrued reputation score.
  • Parameters:
    • _agent: The agent whose reputation score to query
  • Returns: Agent's accrued reputation score & last accrual time.

getAgentReputationConfig(address _agent) → (uint scoreMultiplier, uint baseSupplyOrBorrowRatio)

  • Description: Get agent's current reputation score config.
  • Parameters:
    • _agent: The agent whose reputation score config to query
  • Returns: Agent's reputation score multiplier and base token supply ratio or borrow ratio.

getUtilization() → (uint)

  • Description: Get base token utilization rate
  • Notice:
    • does not accrue interest first
    • returns 0 if total base token supply == 0
    • utilization rate scaling factor: 1e18
    • utilizationRate = totalBorrowed * FACTOR_SCALE / totalSupplied;
    • multiplied by FACTOR_SCALE to maintain a common precision
  • Returns: The utilization rate of the base asset

getSupplyRate(uint _utilization) → (uint64)

  • Description: Get the per second supply rate at current utilization
  • Parameters:
    • _utilization: The utilization to check the supply rate for
  • Notice:
    • does not accrue interest first
  • Returns: The per second supply rate at current utilization.

getBorrowRate(uint _utilization) → (uint64)

  • Description: Get the per second borrow rate at current utilization
  • Parameters:
    • _utilization: The utilization to check the borrow rate for
  • Notice:
    • does not accrue interest first
  • Returns: The per second borrow rate at current utilization.

isBorrowCollateralized(address _agent) → (bool)

  • Description: Check whether an agent has enough collateral to borrow.
  • Parameters:
    • _agent: The agent address to check
  • Returns: Whether the agent has sufficient collateral to borrow.

isLiquidatable(address _agent) → (bool)

  • Description: Check whether an agent's position is undercollateralized and can be liquidated.
  • Parameters:
    • _agent: The agent address to check
  • Returns: Whether an agent's position is undercollateralized and can be liquidated.

baseTrackingAccrued(address _agent) → (uint64)

  • Description: Query the total accrued base rewards for an agent.
  • Parameters:
    • _agent: The agent to query
  • Notice:
    • Rewards are tracked but not automatically claimed
    • Users must claim rewards
  • Returns: The accrued rewards, scaled by BASE_ACCRUAL_SCALE

getAccruedInterestIndices() → (uint64, uint64)

  • Description: Get accrued interest indices for base token supply and borrows.
  • Returns: Accrued baseSupplyIndex and baseBorrowIndex.

getReserves() → (int)

  • Description: Calculates the total amount of protocol reserves of the base token.
  • Returns: The total amount of protocol reserves of the base token.

getCollateralReserves() → (uint)

  • Description: Gets the total balance of protocol collateral reserve for a collateral.
  • Notice: Reverts if collateral reserve is somehow negative, which should not be possible
  • Returns: Available collateral in protocol reserves

collateralBalanceOf(address _agent) → (uint128)

  • Description: Query the current collateral balance of an agent.
  • Parameters:
    • _agent: The agent whose collateral balance to query
  • Returns: The collateral balance of the agent

getPrice(address _priceFeed) → (uint)

  • Description: Get the current price from a feed.
  • Parameters:
    • _priceFeed: The address of a price feed
  • Notice: price is scaled by PRICE_SCALE
  • Returns: The USD price of the asset.

quoteCollateral(uint baseAmount) → (uint)

  • Description: Get the quote for the collateral asset in exchange for an amount of base asset.
  • Parameters:
    • baseAmount: The amount of the base asset to get the quote for
  • Returns: Collateral amount received for given base tokens.

getCollateralInfo() → (CollateralInfo memory)

  • Description: Get complete collateral configuration information.
  • Returns: The collateral config object.

totalsBasic() → (TotalsBasic memory)

  • Description: Get aggregated variables tracked for the entire market.
  • Notice: Used for protocol analytics, dashboard data display and Interest rate calculations
  • Returns: TotalsBasic struct

allowance(address owner, address spender) → (uint)

  • Description: Get the current allowance from owner for spender.
  • Parameters:
    • owner: The address of the account which owns the tokens to be spent
    • spender: The address of the account which may transfer tokens
  • Notice:
    • Compatible with ERC20 interfaces expecting allowance() function
    • Returns max uint for full permission, not a specific amount
  • Returns: Either type(uint256).max (spender is allowed) or 0 (spender is disallowed)

isSupplyPaused()/isTransferPaused()/isWithdrawPaused()/isAbsorbPaused()/isBuyPaused() → (bool)

  • Description: Check whether or not a specific action is paused.
  • Returns: Whether or not a specific action is paused.

baseAccrualScale() → (uint64)

  • Description: Get the base accrual scale constant used for reward calculations.
  • Notice:
    • This is a pure function that returns a constant value
    • Used to scale base reward accrual calculations
  • Returns: The base accrual scale value.

baseIndexScale() → (uint64)

  • Description: Get the base index scale constant.
  • Notice:
    • Used for scaling base supply/borrow indices
    • Typically a large number (e.g., 1e15)
  • Returns: The base index scale value.

factorScale() → (uint64)

  • Description: Get the factor scale constant used for protocol factors.
  • Notice:
    • Used for scaling collateral factors, borrow factors, etc.
    • Typically a large number (e.g., 1e18)
  • Returns: The factor scale value.

priceScale() → (uint64)

  • Description: Get the price scale constant.
  • Notice:
    • Used for scaling asset prices
    • Typically 1e8 (like Chainlink oracles)
  • Returns: The price scale value.

Safety/Security Features

  • Collateral Factors:

    • Borrow Collateral Factor: Maximum borrow against collateral (e.g., 80%, expressed in 0.8e18)
    • Liquidate Collateral Factor: Threshold for liquidation (e.g., 90%, expressed in 0.9e18)
    • Liquidation Factor: Discount applied during liquidations (e.g., 93%, expressed in 0.93e18)
  • Protocol Limits:

    • baseBorrowMin: Minimum borrow amount (to prevent micro-borrows)
    • baseMinForRewards: Minimum balance to earn rewards
    • targetReserves: Target protocol reserves
    • supplyCap: Maximum collateral supply
  • Reentrancy Protection

    • Non-reentrant modifier on all state-changing functions.
    • Prevents recursive calls during execution.
  • Pause Mechanism

    • Governor or pause guardian can pause specific operations:
      • Supply
      • Transfer
      • Withdraw
      • Absorb (liquidations)
      • Buy collateral
  • Access Control

    • Governor: Administrative rights (withdraw reserves, approve managers).
    • Pause Guardian: Emergency pausing rights.
    • Identity Registry: Manages agent registration and permissions.
  • Input Validation

    • Safe math operations to prevent overflows.
    • Boundary checks on all user inputs.
    • Price feed sanity checks.

Security Considerations

  1. Economic Security
  • Utilization rates affect interest rates
  • Protocol fees must balance incentives
  • Reputation system should align with protocol health
  1. Oracle Security
  • Relies on external price feeds
  • Price feed manipulation could affect liquidations
  • Use decentralized, resilient oracle solutions(e.g. chanlink)
  1. Collateral Risk
  • Single collateral system concentrates risk
  • Collateral token volatility affects system health
  • Regular monitoring of collateral quality required
  1. Governance Risks
  • Governor controls critical functions
  • Timelocks and multi-sig recommended for production
  • Emergency pause guardian provides safety

Halo V1 Main Contracts

Comet.sol - Contract that inherits CometMainInterface.sol and is the implementation for most of Comet's core functionalities.

Comet.sol - Contract that inherits CometMainInterface.sol and is the implementation for most of Comet's core functionalities.

CometFactory.sol - Contract that inherits CometConfiguration.sol and Ownable2Step.sol and is used to deploy new versions of Comet.sol. This contract will mainly be called by the Configurator during the governance upgrade process.

CometMainInterface.sol - Abstract contract that inherits CometCore.sol and contains all the functions and events for Comet.sol.

CometCore.sol - Abstract contract that inherits CometStorage.sol, CometConfiguration.sol, and CometMath.sol. This contracts contains functions and constants that are shared between Comet.sol and CometExt.sol.

CometStorage.sol - Contract that defines the storage variables used for the Comet protocol.

CometConfiguration.sol - Contract that defines the configuration structs passed into the constructors for Comet.sol and CometExt.sol.

CometMath.sol - Contract that defines math functions that are used throughout the Comet codebase.

Getting started

  1. Clone the repo
  2. Run yarn install

Env variables

The following env variables are used in the repo. One way to set up these env variables is to create a .env in the root directory of this repo.

Required env variables:

# It is your responsibility to ensure this matches the publicaddress corresponding with the AWS_KMS_KEY_ID.
# Use `AWS_KMS_KEY_ID=... cast wallet address --aws` if in doubt.
DEPLOYER_ADDRESS=

AWS_KMS_KEY_ID=

RPC_URL=
ETHERSCAN_API_KEY=

BASE_TOKEN=""
COLLATERAL=""
IDENTITY_REGISTRY=""
BASE_PRICE_FEED=""
COLLATERAL_PRICE_FEED=""
GOVERNOR_ADDRESS=""
PAUSE_GUARDIAN_ADDRESS=""
PROTOCOL_FEE_RECIPIENT=""

Build contracts

Compiles contracts.

yarn build

Lint contracts

Contract linting is done via Solhint.

yarn lint-contracts
yarn lint-contracts:fix // will attempt to automatically fix errors

Solhint configuration is saved in .solhint.json.

Run forge tests

Running All Test Suites

  • source .env
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv

Running Test Suites Separately

  • source .env
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc IdentityRegistryTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc BaseTokenSupplyTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc CollateralSupplyTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc BaseTokenBorrowTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc BaseTokenRepayTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc BaseTokenWithdrawTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc CollateralWithdrawTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc CollateralLiquidationTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc SupplyAffectsRepScoreTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc BorrowAffectsRepConfigsTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc RepayAppliesDiscountTest
  • forge test --contracts forge/test --rpc-url http://127.0.0.1:8545 -vvv --mc LiquidationResetsRepScoreTest

Deploy contracts

  • source .env
  • forge script script/DeployIdentityRegistryScript.s.sol:DeployIdentityRegistryScript --rpc-url $RPC_URL --broadcast --verify --slow --via-ir --contracts script/ -vvvv --aws
  • forge script script/DeployCometScript.s.sol:DeployCometScript --rpc-url $RPC_URL --broadcast --verify --slow --via-ir --contracts script/ -vvvv --aws
  • forge script script/DeployCometFactoryScript.s.sol:DeployCometFactoryScript --rpc-url $RPC_URL --broadcast --verify --slow --via-ir --contracts script/ -vvvv --aws

License

MIT License

About

Halo Finance is a fork of Compound that creates isolated lending markets where only registered agents (per ERC-8004: Trustless Agents) can borrow.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •