diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..5cc9dba --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,49 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We are committed to providing a harassment-free, inclusive environment for everyone. + +## Our Standards + +### Positive Behaviors + +- Treating all people with respect +- Offering and accepting constructive feedback +- Focusing on collaboration +- Showing empathy towards others + +### Unacceptable Behaviors + +- Harassment and discrimination +- Offensive comments +- Personal attacks +- Public or private harassment +- Sharing others' private information +- Unprofessional conduct + +## Responsibilities + +Project maintainers will: + +- Clarify conduct standards +- Handle complaints fairly +- Remove or edit inappropriate contributions +- Enforce these guidelines + +## Reporting Issues + +Report misconduct to emmanuelpaul152@gmail.com +All complaints will be reviewed and investigated. + +## Enforcement + +Consequences for violations may include: + +- Verbal warning +- Temporary ban +- Permanent project exclusion + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9969bce --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,72 @@ +# Contributing to Bitcoin Yield Aggregator + +## Welcome Contributors! + +We appreciate your interest in contributing to the Bitcoin Yield Aggregator Smart Contract project. This document provides guidelines for contributing effectively. + +## Code of Conduct + +We are committed to providing a friendly, safe, and welcoming environment for all contributors. Please review our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). + +## How to Contribute + +### Reporting Bugs + +1. Check existing issues to avoid duplicates +2. Use the bug report template +3. Provide detailed information + - Clarity version + - Steps to reproduce + - Expected vs. actual behavior + - Any error messages + +### Feature Requests + +1. Check existing issues +2. Clearly describe the proposed feature +3. Explain the use case and potential implementation + +### Pull Request Process + +1. Fork the repository +2. Create a feature branch +3. Write clear, concise commit messages +4. Ensure code follows project standards +5. Add/update tests for new functionality +6. Submit pull request with detailed description + +## Development Setup + +1. Install Clarinet +2. Clone the repository +3. Run `clarinet test` to verify setup +4. Create a new branch for your changes + +## Smart Contract Development Guidelines + +- Follow Clarity best practices +- Write clear, commented code +- Implement comprehensive error handling +- Add unit tests for new functions +- Perform security audits before complex changes + +## Code Review Process + +- All submissions require review +- Provide constructive feedback +- Be respectful and inclusive +- Focus on code quality and security + +## Communication + +- Join our community discussions +- Use GitHub issues for tracking +- Be patient and collaborative + +## Recognition + +Contributors will be acknowledged in the project's documentation. + +## Questions? + +Open an issue or reach out to the maintainers. diff --git a/Clarinet.toml b/Clarinet.toml index d5c0159..a705b16 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -1,21 +1,19 @@ [project] -name = "bitcoin-yield-aggregator" -description = "" +name = 'bitcoin-yield-aggregator' +description = '' authors = [] telemetry = true -cache_dir = "./.cache" - -# [contracts.counter] -# path = "contracts/counter.clar" - +cache_dir = './.cache' +requirements = [] +[contracts.bitcoin-yield] +path = 'contracts/bitcoin-yield.clar' +clarity_version = 2 +epoch = 2.5 [repl.analysis] -passes = ["check_checker"] -check_checker = { trusted_sender = false, trusted_caller = false, callee_filter = false } +passes = ['check_checker'] -# Check-checker settings: -# trusted_sender: if true, inputs are trusted after tx_sender has been checked. -# trusted_caller: if true, inputs are trusted after contract-caller has been checked. -# callee_filter: if true, untrusted data may be passed into a private function without a -# warning, if it gets checked inside. This check will also propagate up to the -# caller. -# More informations: https://www.hiro.so/blog/new-safety-checks-in-clarinet +[repl.analysis.check_checker] +strict = false +trusted_sender = false +trusted_caller = false +callee_filter = false diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..cfc712c --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Emmanuel Paul + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2fa73fc --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# Bitcoin Yield Aggregator Smart Contract + +## Overview + +The Bitcoin Yield Aggregator is a Clarity smart contract designed to manage and aggregate Bitcoin yield across multiple protocols on the Stacks blockchain. This contract allows users to deposit Bitcoin, track yields from different protocols, and withdraw their funds with accrued returns. + +## Features + +- Multi-protocol yield aggregation +- Secure deposit and withdrawal mechanisms +- Dynamic protocol management +- Risk management through protocol deactivation +- Configurable yield calculations + +## Prerequisites + +- Stacks Blockchain +- Clarinet (for local development and testing) +- Basic understanding of Clarity smart contracts + +## Installation + +1. Clone the repository +2. Install Clarinet +3. Run `clarinet console` to interact with the contract + +## Contract Capabilities + +- Add and manage yield protocols +- Deposit funds into supported protocols +- Calculate yield based on protocol APY +- Withdraw funds and yields +- Deactivate protocols for risk management + +## Security Measures + +- Owner-only protocol management +- Input validation for all functions +- Maximum deposit and protocol limits +- Protocol activity tracking + +## Supported Protocols + +- Stacks Core Protocol +- Bitcoin Yield Plus + +## Usage Example + +```clarity +;; Deposit into a protocol +(contract-call? .bitcoin-yield deposit u1 u10000) + +;; Calculate yield +(contract-call? .bitcoin-yield calculate-yield u1 tx-sender) + +;; Withdraw funds +(contract-call? .bitcoin-yield withdraw u1 u5000) +``` + +## Risks and Considerations + +- Yield calculations are simplified +- Actual returns may vary +- Smart contract interactions carry inherent blockchain risks + +## Contributing + +Please read our [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests. + +## License + +This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. + +## Support + +For support, please open an issue in the GitHub repository. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..41f90e0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,51 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.0.x | :white_check_mark: | +| < 1.0 | :x: | + +## Reporting a Vulnerability + +1. Do NOT open public GitHub issues for security vulnerabilities +2. Email emmanuelpaul152@gmail.com with details +3. Include: + - Vulnerability description + - Potential impact + - Steps to reproduce + - Suggested mitigation + +## Security Best Practices + +- Regular code audits +- Comprehensive testing +- Minimal external dependencies +- Input validation +- Error handling +- Principle of least privilege + +## Smart Contract Security Considerations + +- Prevent integer overflow/underflow +- Validate all inputs +- Implement access controls +- Use safe mathematical operations +- Limit external contract interactions + +## Response Process + +1. Acknowledge receipt within 48 hours +2. Investigate vulnerability +3. Develop mitigation strategy +4. Create and test patch +5. Coordinate responsible disclosure + +## Reward Program + +Critical vulnerabilities may be eligible for bounties. + +## Disclaimer + +While we strive for security, no system is completely immune to risks. diff --git a/contracts/bitcoin-yield.clar b/contracts/bitcoin-yield.clar new file mode 100644 index 0000000..2a56633 --- /dev/null +++ b/contracts/bitcoin-yield.clar @@ -0,0 +1,259 @@ +;; title: Bitcoin Yield Aggregator Smart Contract +;; summary: A smart contract for managing and aggregating Bitcoin yield across multiple protocols. +;; description: +;; This smart contract allows users to deposit Bitcoin into supported yield protocols, +;; calculate their yield over time, and withdraw their deposits along with the accrued yield. +;; It includes functionalities for protocol management, user deposit tracking, yield calculation, +;; and risk management through protocol deactivation. The contract ensures proper authorization +;; and enforces protocol constraints to maintain the integrity of the system. + +;; Errors +(define-constant ERR-UNAUTHORIZED (err u1)) +(define-constant ERR-INSUFFICIENT-FUNDS (err u2)) +(define-constant ERR-INVALID-PROTOCOL (err u3)) +(define-constant ERR-WITHDRAWAL-FAILED (err u4)) +(define-constant ERR-DEPOSIT-FAILED (err u5)) +(define-constant ERR-PROTOCOL-LIMIT-REACHED (err u6)) +(define-constant ERR-INVALID-INPUT (err u7)) + +;; Storage: Protocols +(define-map supported-protocols + {protocol-id: uint} + { + name: (string-ascii 50), + base-apy: uint, + max-allocation-percentage: uint, + active: bool + } +) + +;; Storage: Protocol Counter +(define-data-var total-protocols uint u0) + +;; Storage: User Deposits +(define-map user-deposits + {user: principal, protocol-id: uint} + { + amount: uint, + deposit-time: uint + } +) + +;; Storage: Protocol Total Deposits +(define-map protocol-total-deposits + {protocol-id: uint} + {total-deposit: uint} +) + +;; Contract Owner +(define-constant CONTRACT-OWNER tx-sender) + +;; Constants +(define-constant MAX-PROTOCOLS u5) +(define-constant MAX-ALLOCATION-PERCENTAGE u100) +(define-constant BASE-DENOMINATION u1000000) +(define-constant MAX-PROTOCOL-NAME-LENGTH u50) +(define-constant MAX-BASE-APY u10000) ;; 100% +(define-constant MAX-DEPOSIT-AMOUNT u1000000000) ;; Reasonable max deposit + +;; Input Validation Functions +(define-private (is-valid-protocol-id (protocol-id uint)) + (and (> protocol-id u0) (<= protocol-id MAX-PROTOCOLS)) +) + +(define-private (is-valid-protocol-name (name (string-ascii 50))) + (and + (> (len name) u0) + (<= (len name) MAX-PROTOCOL-NAME-LENGTH) + ) +) + +(define-private (is-valid-base-apy (base-apy uint)) + (<= base-apy MAX-BASE-APY) +) + +(define-private (is-valid-allocation-percentage (percentage uint)) + (and (> percentage u0) (<= percentage MAX-ALLOCATION-PERCENTAGE)) +) + +(define-private (is-valid-deposit-amount (amount uint)) + (and (> amount u0) (<= amount MAX-DEPOSIT-AMOUNT)) +) + +;; Authorization Check +(define-private (is-contract-owner (sender principal)) + (is-eq sender CONTRACT-OWNER) +) + +;; Protocol Management +(define-public (add-protocol + (protocol-id uint) + (name (string-ascii 50)) + (base-apy uint) + (max-allocation-percentage uint) +) + (begin + ;; Enhanced Input Validation + (asserts! (is-contract-owner tx-sender) ERR-UNAUTHORIZED) + (asserts! (is-valid-protocol-id protocol-id) ERR-INVALID-INPUT) + (asserts! (is-valid-protocol-name name) ERR-INVALID-INPUT) + (asserts! (is-valid-base-apy base-apy) ERR-INVALID-INPUT) + (asserts! (is-valid-allocation-percentage max-allocation-percentage) ERR-INVALID-INPUT) + (asserts! (< (var-get total-protocols) MAX-PROTOCOLS) ERR-PROTOCOL-LIMIT-REACHED) + + (map-set supported-protocols + {protocol-id: protocol-id} + { + name: name, + base-apy: base-apy, + max-allocation-percentage: max-allocation-percentage, + active: true + } + ) + (var-set total-protocols (+ (var-get total-protocols) u1)) + (ok true) + ) +) + +;; Deposit Functionality +(define-public (deposit + (protocol-id uint) + (amount uint) +) + (let + ( + (protocol (unwrap! + (map-get? supported-protocols {protocol-id: protocol-id}) + ERR-INVALID-PROTOCOL + )) + (current-total-deposits (default-to + {total-deposit: u0} + (map-get? protocol-total-deposits {protocol-id: protocol-id}) + )) + (max-protocol-deposit (/ + (* (get max-allocation-percentage protocol) BASE-DENOMINATION) + u100 + )) + ) + ;; Enhanced Input Validation + (asserts! (is-valid-protocol-id protocol-id) ERR-INVALID-INPUT) + (asserts! (is-valid-deposit-amount amount) ERR-INVALID-INPUT) + (asserts! (get active protocol) ERR-INVALID-PROTOCOL) + (asserts! + (<= (+ (get total-deposit current-total-deposits) amount) max-protocol-deposit) + ERR-PROTOCOL-LIMIT-REACHED + ) + + ;; Update User and Protocol Deposits + (map-set user-deposits + {user: tx-sender, protocol-id: protocol-id} + {amount: amount, deposit-time: block-height} + ) + (map-set protocol-total-deposits + {protocol-id: protocol-id} + {total-deposit: (+ (get total-deposit current-total-deposits) amount)} + ) + + (ok true) + ) +) + +;; Yield Calculation (Simplified Model) +(define-read-only (calculate-yield + (protocol-id uint) + (user principal) +) + (let + ( + (protocol (unwrap! + (map-get? supported-protocols {protocol-id: protocol-id}) + ERR-INVALID-PROTOCOL + )) + (user-deposit (unwrap! + (map-get? user-deposits {user: user, protocol-id: protocol-id}) + ERR-INSUFFICIENT-FUNDS + )) + (blocks-since-deposit (- block-height (get deposit-time user-deposit))) + (annual-yield (/ + (* (get base-apy protocol) (get amount user-deposit)) + BASE-DENOMINATION + )) + ) + ;; Additional input validation + (asserts! (is-valid-protocol-id protocol-id) ERR-INVALID-INPUT) + + (ok (/ + (* annual-yield blocks-since-deposit) + u52596 ;; Approximate blocks in a year + )) + ) +) + +;; Withdrawal Functionality +(define-public (withdraw + (protocol-id uint) + (amount uint) +) + (let + ( + (user-deposit (unwrap! + (map-get? user-deposits {user: tx-sender, protocol-id: protocol-id}) + ERR-INSUFFICIENT-FUNDS + )) + (yield (unwrap! (calculate-yield protocol-id tx-sender) ERR-WITHDRAWAL-FAILED)) + (current-protocol-deposits (default-to + {total-deposit: u0} + (map-get? protocol-total-deposits {protocol-id: protocol-id}) + )) + ) + ;; Enhanced Input Validation + (asserts! (is-valid-protocol-id protocol-id) ERR-INVALID-INPUT) + (asserts! (is-valid-deposit-amount amount) ERR-INVALID-INPUT) + (asserts! (>= (get amount user-deposit) amount) ERR-INSUFFICIENT-FUNDS) + + ;; Update User and Protocol Deposits + (map-set user-deposits + {user: tx-sender, protocol-id: protocol-id} + {amount: (- (get amount user-deposit) amount), deposit-time: block-height} + ) + (map-set protocol-total-deposits + {protocol-id: protocol-id} + {total-deposit: (- (get total-deposit current-protocol-deposits) amount)} + ) + + (ok (+ amount yield)) + ) +) + +;; Risk Management: Protocol Deactivation +(define-public (deactivate-protocol (protocol-id uint)) + (begin + ;; Enhanced Input Validation + (asserts! (is-contract-owner tx-sender) ERR-UNAUTHORIZED) + (asserts! (is-valid-protocol-id protocol-id) ERR-INVALID-INPUT) + (map-set supported-protocols + {protocol-id: protocol-id} + (merge + (unwrap! + (map-get? supported-protocols {protocol-id: protocol-id}) + ERR-INVALID-PROTOCOL + ) + {active: false} + ) + ) + (var-set total-protocols (- (var-get total-protocols) u1)) + (ok true) + ) +) + +;; Initialization with Error Checking +(define-public (initialize-protocols) + (begin + (try! (add-protocol u1 "Stacks Core Protocol" u500 u20)) + (try! (add-protocol u2 "Bitcoin Yield Plus" u750 u30)) + (ok true) + ) +) + +;; Contract Initialization +(try! (initialize-protocols)) \ No newline at end of file diff --git a/tests/bitcoin-yield.test.ts b/tests/bitcoin-yield.test.ts new file mode 100644 index 0000000..4bb9cf3 --- /dev/null +++ b/tests/bitcoin-yield.test.ts @@ -0,0 +1,21 @@ + +import { describe, expect, it } from "vitest"; + +const accounts = simnet.getAccounts(); +const address1 = accounts.get("wallet_1")!; + +/* + The test below is an example. To learn more, read the testing documentation here: + https://docs.hiro.so/stacks/clarinet-js-sdk +*/ + +describe("example tests", () => { + it("ensures simnet is well initalised", () => { + expect(simnet.blockHeight).toBeDefined(); + }); + + // it("shows an example", () => { + // const { result } = simnet.callReadOnlyFn("counter", "get-counter", [], address1); + // expect(result).toBeUint(0); + // }); +});