### Hardhat Testing Framework Example Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Illustrates a basic test structure using Hardhat and Chai for smart contract testing. Includes setup and assertion examples. ```typescript import { expect } from "chai"; import { ethers } from "hardhat"; describe("MyContract", function () { it("should return the correct value", async function () { const MyContract = await ethers.getContractFactory("MyContract"); const myContract = await MyContract.deploy(); await myContract.waitForDeployment(); const value = await myContract.getValue(); expect(value).to.equal(42); }); }); ``` -------------------------------- ### Start dApp Development Server Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Start the development server for the dApp frontend. This command is for the minimal dApp component. ```bash cd dapp && pnpm dev ``` -------------------------------- ### Build Solidity Contracts Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Navigate to the solidity directory and run the build command. Ensure all dependencies are installed via pnpm. ```bash cd solidity && pnpm build ``` -------------------------------- ### Install Project Dependencies with pnpm Source: https://github.com/mezo-org/musd/blob/main/dapp/README.md Installs all necessary project dependencies using pnpm. Ensure pnpm is installed globally before running. ```bash pnpm install ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/mezo-org/musd/blob/main/README.md Installs project dependencies using pnpm. Ensure you have pnpm installed and follow the provided link for installation instructions. ```bash pnpm install --frozen-lockfile cd solidity pnpm install --frozen-lockfile ``` -------------------------------- ### Run Project Tests Source: https://github.com/mezo-org/musd/blob/main/README.md Executes the project's tests after navigating to the 'solidity' directory. Ensure all dependencies are installed before running tests. ```bash cd solidity pnpm test ``` -------------------------------- ### Run Local Hardhat Node for Solidity Development Source: https://github.com/mezo-org/musd/blob/main/dapp/README.md Starts a local Hardhat network for testing Solidity smart contracts. Navigate to the 'solidity' directory before running this command. ```bash cd ../solidity pnpm node ``` -------------------------------- ### Install Pre-commit Hooks Source: https://github.com/mezo-org/musd/blob/main/README.md Installs pre-commit hooks for automated code issue detection. Requires the 'pre-commit' tool to be installed first, which can be done via Homebrew. ```bash brew install pre-commit pre-commit install ``` -------------------------------- ### Install Slither Static Analyzer Source: https://github.com/mezo-org/musd/blob/main/solidity/README.md Installs the Slither static analysis tool locally using Homebrew. Slither helps identify vulnerabilities in Solidity code. ```bash brew install slither ``` -------------------------------- ### Use ethers.js v6 for Blockchain Interactions Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Example of using ethers.js v6 for interacting with smart contracts. Ensure the library is installed and imported correctly. ```typescript import { ethers } from "ethers"; async function getBalance(address: string): Promise { const provider = new ethers.JsonRpcProvider("http://localhost:8545"); const balance = await provider.getBalance(address); return balance; } ``` -------------------------------- ### Deploy Solidity Contracts Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Deploy the smart contracts to a specified network using the deploy command. The example shows deployment to the 'matsnet' network. ```bash cd solidity && pnpm deploy --network matsnet ``` -------------------------------- ### Setup for Recovery Mode Tests Source: https://github.com/mezo-org/musd/blob/main/docs/tests.md Ensures at least two troves exist and then drops the collateral price to trigger recovery mode. This setup is crucial for testing recovery mode behavior. ```javascript async function recoveryModeSetup() { // data setup const transactions = [ { musdAmount: "10,000", sender: alice.wallet, }, { musdAmount: "20,000", sender: bob.wallet, }, ] for (let i = 0; i < transactions.length; i++) { await openTrove(contracts, transactions[i]) } // collateral value drops from 50,000 to 10,000 const price = to1e18("10,000") await contracts.mockAggregator.connect(deployer.wallet).setPrice(price) expect(await contracts.troveManager.checkRecoveryMode(price)).to.equal(true) } beforeEach(async () => { // fixtureBorrowerOperations has a mock trove manager so we can change rates cachedTestSetup = await loadFixture(fixtureBorrowerOperations) testSetup = { ...cachedTestSetup } contracts = testSetup.contracts // users alice = testSetup.users.alice bob = testSetup.users.bob carol = testSetup.users.carol deployer = testSetup.users.deployer await recoveryModeSetup() }) ``` -------------------------------- ### Run mUSD Dapp Locally Source: https://github.com/mezo-org/musd/blob/main/dapp/README.md Starts the mUSD Dapp in development mode for local testing. This command is used for active development cycles. ```bash pnpm dev ``` -------------------------------- ### MUSD Protocol Setup and Trove Operations Source: https://context7.com/mezo-org/musd/llms.txt Initializes contract instances and demonstrates various trove management operations including opening, adding/withdrawing collateral and debt, repaying, adjusting, refinancing, closing, and claiming collateral. Also includes governance actions for proposing and approving borrowing rates. ```typescript import { ethers } from "hardhat" import { to1e18 } from "./test/utils" // Deployed contract instances (addresses from deployment artifacts) const borrowerOperations = await ethers.getContractAt( "BorrowerOperations", "0x" ) const hintHelpers = await ethers.getContractAt( "HintHelpers", "0x" ) const sortedTroves = await ethers.getContractAt( "SortedTroves", "0x" ) const troveManager = await ethers.getContractAt( "TroveManager", "0x" ) const [alice] = await ethers.getSigners() // --- 1. openTrove --- // Borrow 10,000 MUSD with a 150% ICR. const musdAmount = to1e18("10000") const price = await (await ethers.getContractAt("PriceFeed", "0x")).fetchPrice() const fee = await borrowerOperations.getBorrowingFee(musdAmount) const gasComp = await troveManager.MUSD_GAS_COMPENSATION() const compositeDebt = musdAmount + fee + gasComp const collNeeded = (compositeDebt * to1e18("150")) / (price * 100n) const { 0: approxHint } = await hintHelpers.getApproxHint( (collNeeded * to1e18("100")) / compositeDebt, // NICR BigInt(Math.ceil(Math.sqrt(Number(await troveManager.getTroveOwnersCount()))) * 15 + 1), 12345n ) const { 0: upperHint, 1: lowerHint } = await sortedTroves.findInsertPosition( (collNeeded * to1e18("100")) / compositeDebt, approxHint, approxHint ) const openTx = await borrowerOperations .connect(alice) .openTrove(musdAmount, upperHint, lowerHint, { value: collNeeded }) // Event emitted: TroveCreated(alice.address, arrayIndex) // Event emitted: TroveUpdated(alice.address, compositeDebt, 0, collNeeded, stake, interestRate, timestamp, 0) // --- 2. addColl --- const extraColl = to1e18("0.5") await borrowerOperations.connect(alice).addColl(upperHint, lowerHint, { value: extraColl }) // --- 3. withdrawColl --- await borrowerOperations.connect(alice).withdrawColl(to1e18("0.1"), upperHint, lowerHint) // --- 4. withdrawMUSD — borrow more --- await borrowerOperations.connect(alice).withdrawMUSD(to1e18("500"), upperHint, lowerHint) // --- 5. repayMUSD --- // Alice must hold sufficient MUSD await borrowerOperations.connect(alice).repayMUSD(to1e18("500"), upperHint, lowerHint) // --- 6. adjustTrove — simultaneous coll + debt change --- // Withdraw 200 MUSD while sending 0.1 BTC extra collateral await borrowerOperations .connect(alice) .adjustTrove(0n, to1e18("200"), true, upperHint, lowerHint, { value: to1e18("0.1") }) // --- 7. refinance — move to current global interest rate --- await borrowerOperations.connect(alice).refinance(upperHint, lowerHint) // --- 8. closeTrove --- // Alice must hold (debt - GAS_COMPENSATION) MUSD await borrowerOperations.connect(alice).closeTrove() // --- 9. claimCollateral — after full redemption or liquidation surplus --- await borrowerOperations.connect(alice).claimCollateral() // --- Governance: propose and approve a new borrowing rate (7-day delay) --- const council = await ethers.getSigner("0x") await borrowerOperations.connect(council).proposeBorrowingRate(to1e18("1") / 200n) // 0.5% // ... wait 7 days on-chain ... await borrowerOperations.connect(council).approveBorrowingRate() ``` -------------------------------- ### Assert User State Changes Source: https://github.com/mezo-org/musd/blob/main/docs/tests.md Example of asserting changes in user state after an operation, comparing `before` and `after` values for collateral and BTC balances. ```typescript expect(alice.collateral.after).to.equal(alice.collateral.before + collateralTopUp) expect(alice.btc.after).to.equal(alice.btc.before - collateralTopUp) ``` -------------------------------- ### Prepare Environment Variables Source: https://github.com/mezo-org/musd/blob/main/solidity/README.md Manually creates a `.env` file from the `.env.example` template. This is useful for setting up environment variables required for deployment or testing. ```bash pnpm run prepare:env ``` -------------------------------- ### Run Open Troves Scenario Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Initiates the scale testing by opening troves to establish initial state. ```bash npx hardhat run scripts/scale-testing/scenarios/open-troves.ts --network matsnet_fuzz ``` -------------------------------- ### Build dApp Frontend Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Build the React frontend for the dApp. This command is for the minimal dApp component. ```bash cd dapp && pnpm build ``` -------------------------------- ### Initialize State Tracking Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Sets up the state tracking system, initializing account state tracking in scale-testing/account-state-matsnet.json. ```bash npx hardhat run scripts/scale-testing/init-state-tracking.ts --network matsnet_fuzz ``` -------------------------------- ### Test dApp Frontend Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Run tests for the dApp frontend. This command is for the minimal dApp component. ```bash cd dapp && pnpm test ``` -------------------------------- ### Expect Revert with openTrove Source: https://github.com/mezo-org/musd/blob/main/docs/tests.md Example of testing for a reverted transaction when calling `openTrove` with specific parameters that should cause an error. Uses `expect(...).to.be.revertedWith()`. ```typescript await expect( openTrove( contracts, { musdAmount: "100,000", sender: deployer.wallet, }) ).to.be.revertedWith("MUSD: Caller not allowed to mint") ``` -------------------------------- ### Start and Finalize PCV Role Changes Source: https://context7.com/mezo-org/musd/llms.txt Initiates a time-delayed change of governance roles (council and treasury) and finalizes the change after the delay period. Requires owner privileges. ```typescript // --- Governance role change (time-delayed) --- await pcv.connect(owner).startChangingRoles("0x", "0x") // Wait governanceTimeDelay seconds... await pcv.connect(owner).finalizeChangingRoles() // Event: RolesSet(newCouncil, newTreasury) ``` -------------------------------- ### Set Price Using Mock Aggregator Source: https://github.com/mezo-org/musd/blob/main/docs/tests.md Example of calling the `setPrice` function on the mock aggregator contract to change the price feed value during tests. Requires connecting with the deployer account. ```typescript await contracts.mockAggregator.connect(deployer).setPrice(price) ``` -------------------------------- ### Deploy Contracts Source: https://github.com/mezo-org/musd/blob/main/README.md Deploys smart contracts to the 'matsnet' network. Before deployment, copy and fill in the '.env.example' file with your environment-specific values. Deploys to the current deployment path; delete or archive the 'deployments/matsnet' directory for a fresh deployment. ```bash cd solidity cp .env.example .env pnpm run deploy --network matsnet ``` -------------------------------- ### Interact with TroveManager Contract Source: https://context7.com/mezo-org/musd/llms.txt Get contract instances for TroveManager, HintHelpers, and SortedTroves. Read trove state, system-wide stats, and pending rewards. Use this to manage and query trove data. ```typescript const troveManager = await ethers.getContractAt("TroveManager", "0x") const hintHelpers = await ethers.getContractAt("HintHelpers", "0x") const sortedTroves = await ethers.getContractAt("SortedTroves", "0x") // --- Read trove state --- const [coll, principal, interestOwed, stake, status, interestRate, lastUpdate, maxCapacity] = await troveManager.Troves(alice.address) // status: 0=nonExistent, 1=active, 2=closedByOwner, 3=closedByLiquidation, 4=closedByRedemption const { coll: c, principal: p, interest: i } = await troveManager.getEntireDebtAndColl(alice.address) const currentICR = await troveManager.getCurrentICR(alice.address, price) const tcr = await troveManager.getTCR(price) const isRecovery = await troveManager.checkRecoveryMode(price) // --- Pending rewards (from redistribution) --- const pendingColl = await troveManager.getPendingCollateral(alice.address) const { pendingPrincipal, pendingInterest } = await troveManager.getPendingDebt(alice.address) // --- System-wide stats --- const totalColl = await troveManager.getEntireSystemColl() const totalDebt = await troveManager.getEntireSystemDebt() const numTroves = await troveManager.getTroveOwnersCount() ``` -------------------------------- ### Open Trove with Hint Calculation Source: https://github.com/mezo-org/musd/blob/main/docs/README.md Demonstrates how to open a new Trove by calculating necessary hints for insertion into the sorted Troves linked list. This process involves estimating debt, calculating the nominal collateralization ratio (NICR), and using helper contracts to find appropriate upper and lower hints for the `openTrove` function. ```typescript const debtAmount = to1e18(2000) const assetAmount = to1e18(10) const gasCompensation = await troveManager.MUSD_GAS_COMPENSATION() const expectedFee = await troveManager.getBorrowingFeeWithDecay(debtAmount) const expectedTotalDebt = debtAmount + expectedFee + gasCompensation const nicr = (assetAmount * to1e18(100)) / expectedTotalDebt const numTroves = Number(await sortedTroves.getSize()) const numTrials = BigInt(Math.ceil(Math.sqrt(numTroves))) * 15n const randomSeed = Math.ceil(Math.random() * 100000) const { 0: approxHint } = await hintHelpers.getApproxHint( nicr, numTrials, randomSeed, ) const { 0: upperHint, 1: lowerHint } = await sortedTroves.findInsertPosition( nicr, approxHint, approxHint, ) await borrowerOperations .connect(carol.wallet) .openTrove(maxFeePercentage, debtAmount, upperHint, lowerHint, { value: assetAmount, }) ``` -------------------------------- ### Build mUSD Dapp for Production Source: https://github.com/mezo-org/musd/blob/main/dapp/README.md Creates an optimized production build of the mUSD Dapp. This is typically done before deployment. ```bash pnpm build ``` -------------------------------- ### Test Solidity Contracts Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Execute tests for the smart contracts by navigating to the solidity directory and running the test command. This uses the Hardhat testing framework. ```bash cd solidity && pnpm test ``` -------------------------------- ### Use Upgradeable Contracts Pattern Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Utilize OpenZeppelin's upgradeable contracts pattern, which requires an initializer function to set initial state. ```solidity import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract MyContract is Initializable, Ownable { function initialize() public initializer { // Initialization logic __Ownable_init(); } } ``` -------------------------------- ### Initialize PCV Bootstrap Loan Source: https://context7.com/mezo-org/musd/llms.txt Initializes the bootstrap loan by minting MUSD and depositing it into the Stability Pool. This is a one-time operation at deployment and requires owner privileges. ```typescript // --- Initialize bootstrap loan (one-time at deployment) --- // Mints 100M MUSD to PCV then deposits to StabilityPool await pcv.connect(owner).initializeDebt() // Event: PCVDepositSP(pcvAddress, 1e26, 0) ``` -------------------------------- ### Import OpenZeppelin Contracts Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Import standard functionalities from OpenZeppelin contracts. This is a common practice for secure and efficient development. ```solidity import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; ``` -------------------------------- ### Run Project Tests Source: https://github.com/mezo-org/musd/blob/main/solidity/README.md Executes the project's test suite. This command runs all defined tests to ensure contract functionality. ```bash pnpm test ``` -------------------------------- ### Deploy Contracts to Sepolia (Matsnet) Source: https://github.com/mezo-org/musd/blob/main/solidity/README.md Deploys contracts to the Sepolia testnet, referred to as 'matsnet' in this project. Requires proper `.env` configuration for network access. ```bash pnpm run deploy --network matsnet ``` -------------------------------- ### Generate Test Wallets Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Creates wallet accounts for testing and stores their encrypted private keys. A password.txt file is generated for decryption. Ensure password.txt exists if using existing wallets. ```bash npx hardhat run scripts/scale-testing/generate-wallets.ts --network matsnet_fuzz ``` -------------------------------- ### Deploy Contracts for Testing Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Deploys a new set of contracts to the matsnet_fuzz network for scale testing. Consider using existing contracts to preserve state. ```bash pnpm run deploy --network matsnet_fuzz ``` -------------------------------- ### Implement Access Control Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Use OpenZeppelin's Ownable contract for basic ownership-based access control. Ensure proper access controls are implemented for sensitive functions. ```solidity import "@openzeppelin/contracts/access/Ownable.sol"; contract MyContract is Ownable { function setOwner(address newOwner) public onlyOwner { // ... } } ``` -------------------------------- ### Query Accounts with StateManager Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Demonstrates using the StateManager class to find accounts matching specific criteria, such as MUSD balance and trove status. ```typescript const accounts = stateManager.getAccounts({ minMusdBalance: "1000", hasTrove: true, notUsedInTest: "redemption-test", }) ``` -------------------------------- ### Test Pre-commit Hooks Source: https://github.com/mezo-org/musd/blob/main/README.md Manually invokes pre-commit hooks for testing or debugging. Use '--all-files' to run hooks on all files or '--files ' for specific files. ```bash # Execute hooks for all files: pre-commit run --all-files # Execute hooks for specific files: pre-commit run --files ``` -------------------------------- ### Configure PCV Fee Recipients and Split Source: https://context7.com/mezo-org/musd/llms.txt Sets the MUSD fee recipient and the BTC redemption fee recipient, and configures the fee split percentage. Requires owner privileges. ```typescript // --- Governance setup (owner / council / treasury) --- const owner = await ethers.getSigner("0x") // Point MUSD fees to the savings rate vault await pcv.connect(owner).setFeeRecipient("0x") // Point BTC redemption fees to the BTC handler await pcv.connect(owner).setBTCRecipient("0x") // Set split: 70% to savings vault, 30% to repay bootstrap loan await pcv.connect(owner).setFeeSplit(70) ``` -------------------------------- ### Deploy Contracts (In-Memory) Source: https://github.com/mezo-org/musd/blob/main/solidity/README.md Deploys contracts to an in-memory Hardhat network, which is suitable for local development and testing without network costs. ```bash pnpm run deploy ``` -------------------------------- ### openTrove Source: https://context7.com/mezo-org/musd/llms.txt Opens a new trove by depositing collateral and borrowing MUSD. Requires calculating the necessary collateral based on the desired MUSD amount, current price, and minimum collateral ratio. ```APIDOC ## openTrove ### Description Opens a new trove by depositing collateral and borrowing MUSD. Requires calculating the necessary collateral based on the desired MUSD amount, current price, and minimum collateral ratio. ### Method POST ### Endpoint /trove/open ### Parameters #### Path Parameters - **alice** (address) - The address of the user opening the trove. #### Request Body - **musdAmount** (uint256) - The amount of MUSD to borrow. - **upperHint** (uint256) - Hint for trove insertion position. - **lowerHint** (uint256) - Hint for trove insertion position. - **collateral** (uint256) - The amount of collateral (e.g., BTC) to deposit. ### Request Example ```typescript const musdAmount = to1e18("10000") const price = await (await ethers.getContractAt("PriceFeed", "0x")).fetchPrice() const fee = await borrowerOperations.getBorrowingFee(musdAmount) const gasComp = await troveManager.MUSD_GAS_COMPENSATION() const compositeDebt = musdAmount + fee + gasComp const collNeeded = (compositeDebt * to1e18("150")) / (price * 100n) const { 0: approxHint } = await hintHelpers.getApproxHint( (collNeeded * to1e18("100")) / compositeDebt, // NICR BigInt(Math.ceil(Math.sqrt(Number(await troveManager.getTroveOwnersCount()))) * 15 + 1), 12345n ) const { 0: upperHint, 1: lowerHint } = await sortedTroves.findInsertPosition( (collNeeded * to1e18("100")) / compositeDebt, approxHint, approxHint ) const openTx = await borrowerOperations .connect(alice) .openTrove(musdAmount, upperHint, lowerHint, { value: collNeeded }) ``` ### Response #### Success Response (200) - **TroveCreated** (event) - Emitted when a new trove is successfully created. - **TroveUpdated** (event) - Emitted when the trove's state is updated after creation. ``` -------------------------------- ### Redeem Collateral using TroveManager and HintHelpers Source: https://context7.com/mezo-org/musd/llms.txt Redeem MUSD for collateral by first computing hints using HintHelpers and SortedTroves to find the optimal trove for redemption. This avoids expensive on-chain searches. ```typescript // --- redeemCollateral --- // Compute hints via HintHelpers first const redemptionAmount = to1e18("1000") // burn 1,000 MUSD const currentPrice = await priceFeed.fetchPrice() const { firstRedemptionHint, partialRedemptionHintNICR, truncatedAmount } = await hintHelpers.getRedemptionHints(redemptionAmount, currentPrice, 0n) const { 0: upperPartial, 1: lowerPartial } = await sortedTroves.findInsertPosition( partialRedemptionHintNICR, firstRedemptionHint, firstRedemptionHint ) if (truncatedAmount > 0n) { await troveManager.redeemCollateral( truncatedAmount, firstRedemptionHint, upperPartial, lowerPartial, partialRedemptionHintNICR, 50n // maxIterations ) } // Event: Redemption(attemptedMUSD, actualMUSD, collSent, collFee) ``` -------------------------------- ### Open Trove with EIP-712 Signature Source: https://context7.com/mezo-org/musd/llms.txt Demonstrates building an EIP-712 domain and signature for opening a trove. Requires the BorrowerOperationsSignatures contract address and user's signature. ```typescript import { ethers } from "hardhat" import { to1e18 } from "./test/utils" const bosig = await ethers.getContractAt( "BorrowerOperationsSignatures", "0x" ) // --- Build EIP-712 domain --- const domain = { name: "BorrowerOperationsSignatures", version: "1", chainId: (await ethers.provider.getNetwork()).chainId, verifyingContract: await bosig.getAddress(), } // --- openTroveWithSignature --- const nonce = await bosig.getNonce(carol.address) const deadline = BigInt(Math.floor(Date.now() / 1000)) + 3600n // +1 hour const openTroveTypes = { OpenTrove: [ { name: "assetAmount", type: "uint256" }, { name: "debtAmount", type: "uint256" }, { name: "borrower", type: "address" }, { name: "recipient", type: "address" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" }, ], } const collateral = to1e18("1") const debtAmount = to1e18("8000") const openTroveValues = { assetAmount: collateral, debtAmount, borrower: carol.address, recipient: carol.address, nonce, deadline, } const carolSignature = await carol.signTypedData(domain, openTroveTypes, openTroveValues) // A third-party (bob) opens a trove on carol's behalf await bosig .connect(bob) .openTroveWithSignature(debtAmount, upperHint, lowerHint, carol.address, carol.address, carolSignature, deadline, { value: collateral, }) ``` -------------------------------- ### Calculate Redemption Hints and Perform Redemption Source: https://github.com/mezo-org/musd/blob/main/docs/README.md This snippet demonstrates how to obtain redemption hints, including the first trove to redeem from, the nominal ICR after a partial redemption, and the maximum redeemable amount. It then uses these hints to perform the redemption if a valid amount is available. ```typescript const { firstRedemptionHint, // First trove to redeem from partialRedemptionHintNICR, // Nominal ICR of the last trove after partial redemption truncatedAmount // Maximum amount that can be redeemed } = await hintHelpers.getRedemptionHints( redemptionAmount, currentPrice, maxIterations ); // Get insert position hints const { upperPartialRedemptionHint, lowerPartialRedemptionHint } = await sortedTroves.findInsertPosition( partialRedemptionHintNICR, redeemerAddress, redeemerAddress ); // Perform redemption if (truncatedAmount > 0) { await troveManager.redeemCollateral( truncatedAmount, firstRedemptionHint, upperPartialRedemptionHint, lowerPartialRedemptionHint, partialRedemptionHintNICR, maxIterations ); } ``` -------------------------------- ### Run Slither Analysis Source: https://github.com/mezo-org/musd/blob/main/solidity/README.md Performs a static analysis of the project's Solidity code using Slither. This helps in detecting potential security issues. ```bash slither . ``` -------------------------------- ### Set New Contract Addresses in System Source: https://github.com/mezo-org/musd/blob/main/docs/migration.md Use the `execute` function with a new contract address fetching helper to update system contracts with the addresses of the newly deployed contract versions. ```typescript const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { execute, isHardhatNetwork, isFuzzTestingNetwork } = await setupDeploymentBoilerplate(hre) const { borrowerOperations, sortedTroves, troveManager } = await newFetchAllDeployedContracts(isHardhatNetwork, isFuzzTestingNetwork) await execute( "NewHintHelpers", "setAddresses", await borrowerOperations.getAddress(), await sortedTroves.getAddress(), await troveManager.getAddress(), ) } ``` -------------------------------- ### getEntireSystemDebt() Source: https://github.com/mezo-org/musd/blob/main/docs/README.md Calculates and returns the total MUSD debt across the entire system, including both the Active Pool and the Default Pool. ```APIDOC ## getEntireSystemDebt() ### Description Returns the total MUSD debt assigned across all Troves in the system, summing up debt from both the Active Pool and the Default Pool. ### Method CALL ``` -------------------------------- ### Interact with StabilityPool Contract Source: https://context7.com/mezo-org/musd/llms.txt Demonstrates how to connect to the StabilityPool and MUSD contracts, deposit MUSD, and read pool state. Ensure MUSD is approved before depositing. ```typescript const stabilityPool = await ethers.getContractAt("StabilityPool", "0x") const musd = await ethers.getContractAt("MUSD", "0x") // --- Deposit MUSD to earn liquidation collateral gains --- const depositAmount = to1e18("5000") await musd.connect(alice).approve(await stabilityPool.getAddress(), depositAmount) await stabilityPool.connect(alice).provideToSP(depositAmount) // Event: UserDepositChanged(alice.address, 5000e18) ``` ```typescript // --- Read current deposit and gains --- const compoundedDeposit = await stabilityPool.getCompoundedMUSDDeposit(alice.address) const collGain = await stabilityPool.getDepositorCollateralGain(alice.address) const totalMUSD = await stabilityPool.getTotalMUSDDeposits() const poolCollateral = await stabilityPool.getCollateralBalance() ``` ```typescript // --- Partial withdrawal (also triggers collateral gain payout) --- await stabilityPool.connect(alice).withdrawFromSP(to1e18("1000")) // Sends 1000 MUSD back + accumulated BTC gain to alice ``` ```typescript // --- Redirect accumulated BTC gain directly into alice's trove --- // (alice must have an active trove) await stabilityPool .connect(alice) .withdrawCollateralGainToTrove(upperHint, lowerHint) // Event: CollateralGainWithdrawn(alice.address, gainAmount, musdLoss) ``` ```typescript // --- Pool state for monitoring --- const P = await stabilityPool.P() // running product (precision tracker) const currentEpoch = await stabilityPool.currentEpoch() const currentScale = await stabilityPool.currentScale() const snapshot = await stabilityPool.depositSnapshots(alice.address) // snapshot.S = collateral sum at deposit time; snapshot.P = product at deposit time ``` -------------------------------- ### Fund Test Wallets Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Distributes funds to the generated test wallets using the MATSNET_PRIVATE_KEY configured in your .env file. ```bash npx hardhat run scripts/scale-testing/fund-wallets.ts --network matsnet_fuzz ``` -------------------------------- ### Add Collateral to Troves Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Executes the scenario to add collateral to existing troves. ```bash npx hardhat run scripts/scale-testing/scenarios/add-collateral.ts --network matsnet_fuzz ``` -------------------------------- ### Generate Code Coverage Report Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Generate a code coverage report for the Solidity contracts. This helps in assessing the thoroughness of tests. ```bash cd solidity && pnpm coverage ``` -------------------------------- ### Liquidate Risky Troves Source: https://github.com/mezo-org/musd/blob/main/docs/scaleTesting.md Executes the scenario to liquidate troves that have become risky. ```bash npx hardhat run scripts/scale-testing/scenarios/liquidate-troves.ts --network matsnet_fuzz ``` -------------------------------- ### Format Solidity Code Source: https://github.com/mezo-org/musd/blob/main/CLAUDE.md Format the Solidity code according to project standards using prettier. Use the 'format:fix' variant to automatically fix formatting issues. ```bash cd solidity && pnpm format ``` ```bash pnpm format ``` -------------------------------- ### HintHelpers Contract Functions Source: https://context7.com/mezo-org/musd/llms.txt Utilizing HintHelpers for off-chain computation of hints to optimize trove operations. ```APIDOC ## HintHelpers Contract Functions ### Description The `HintHelpers` contract provides read-only functions to compute hints for the `SortedTroves` linked list, optimizing on-chain operations by avoiding expensive searches. ### Compute Nominal CR Calculate the Nominal Collateralization Ratio (NICR) which is price-independent. ```typescript const hintHelpers = await ethers.getContractAt("HintHelpers", "0x") // Example values const collateral = to1e18("2") // 2 units of collateral const compositeDebt = to1e18("5000") + gasComp + fee // MUSD + fees // Compute NICR const nicr = await hintHelpers.computeNominalCR(collateral, compositeDebt) ``` ### Get Approximate Hint Perform a probabilistic search for a hint address within the `SortedTroves` list. ```typescript const numTroves = await troveManager.getTroveOwnersCount() const numTrials = BigInt(Math.ceil(Math.sqrt(Number(numTroves))) * 15) + 1n const seed = BigInt(Math.ceil(Math.random() * 100_000)) // Get approximate hint based on NICR const { hintAddress, diff } = await hintHelpers.getApproxHint(nicr, numTrials, seed) ``` ### Find Insert Position Determine the exact insertion position in the `SortedTroves` list using hints. ```typescript const sortedTroves = await ethers.getContractAt("SortedTroves", "0x") // Find insert position using NICR and hint address const { 0: upperHint, 1: lowerHint } = await sortedTroves.findInsertPosition( nicr, hintAddress, hintAddress ) ``` ### Get Redemption Hints Simulate redemption traversals to find the best hints for redeeming MUSD. ```typescript const price = await priceFeed.fetchPrice() // Get hints for redeeming 2000 MUSD const { firstRedemptionHint, partialRedemptionHintNICR, truncatedAmount } = await hintHelpers.getRedemptionHints( to1e18("2000"), // MUSD amount to redeem price, 10n // cap at 10 troves; 0 = uncapped ) // truncatedAmount is the amount to use to avoid partial-below-minNetDebt reverts ``` ### Compute CR Calculate the Collateralization Ratio (CR) including the current price. ```typescript // Example values const collateral = to1e18("2") const compositeDebt = to1e18("5000") + gasComp + fee const price = await priceFeed.fetchPrice() // Compute CR (returns value in 1e18 precision, e.g., 1.1e18 = 110%) const icr = await hintHelpers.computeCR(collateral, compositeDebt, price) ``` ``` -------------------------------- ### Adjust Trove with EIP-712 Signature Source: https://context7.com/mezo-org/musd/llms.txt Shows how to construct an EIP-712 signature for adjusting an existing trove. Ensure correct parameters for debt increase/decrease and collateral changes. ```typescript const adjustTypes = { AdjustTrove: [ { name: "collWithdrawal", type: "uint256" }, { name: "debtChange", type: "uint256" }, { name: "isDebtIncrease", type: "bool" }, { name: "assetAmount", type: "uint256" }, { name: "borrower", type: "address" }, { name: "recipient", type: "address" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" }, ], } const adjustNonce = await bosig.getNonce(carol.address) const adjustSig = await carol.signTypedData(domain, adjustTypes, { collWithdrawal: 0n, debtChange: to1e18("500"), isDebtIncrease: true, assetAmount: 0n, borrower: carol.address, recipient: carol.address, nonce: adjustNonce, deadline, }) await bosig .connect(bob) .adjustTroveWithSignature( 0n, to1e18("500"), true, upperHint, lowerHint, carol.address, carol.address, adjustSig, deadline ) ```