diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..57b23d7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,69 @@ +# Code of Conduct + +## Our Pledge +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +### Positive Behavior +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +### Unacceptable Behavior +* The use of sexualized language or imagery +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting +* Manipulation of smart contract vulnerabilities +* Intentional exploitation of security flaws +* Malicious attacks on the network or contract + +## Project Maintainers' Responsibilities +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to: +* Remove, edit, or reject comments, commits, code, issues, and other contributions +* Ban temporarily or permanently any contributor for behaviors deemed inappropriate, threatening, offensive, or harmful +* Protect users and stakeholders of the smart contract +* Maintain the integrity of the codebase + +## Scope +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +## Enforcement + +### Reporting +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated promptly and fairly. + +### Enforcement Guidelines +Project maintainers will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +1. **Correction** + - Community Impact: Use of inappropriate language or other behavior deemed unprofessional. + - Consequence: Private, written warning with clarity of violation and explanation of why the behavior was inappropriate. + +2. **Warning** + - Community Impact: A violation through a single incident or series of actions. + - Consequence: Warning with consequences for continued behavior. + +3. **Temporary Ban** + - Community Impact: A serious violation of community standards. + - Consequence: Temporary ban from any sort of interaction or public communication with the community. + +4. **Permanent Ban** + - Community Impact: Demonstrating a pattern of violation of community standards. + - Consequence: Permanent ban from any sort of public interaction within the community. + +## Smart Contract Specific Guidelines +1. Report security vulnerabilities responsibly +2. Do not attempt to exploit contract weaknesses +3. Respect the financial stakes of other users +4. Follow proper upgrade and governance procedures +5. Maintain transparency in proposal creation and voting + +## Attribution +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..48d6791 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,108 @@ +# Contributing to Stacks Fund Smart Contract + +## Welcome! + +Thank you for considering contributing to the Stacks Fund Smart Contract. This document provides guidelines and workflows for contributing to this project. + +## Code of Conduct + +This project adheres to our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. + +## How Can I Contribute? + +### Reporting Bugs + +Before submitting a bug report: + +1. Check the existing issues +2. Test with the latest version +3. Collect relevant information: + - Steps to reproduce + - Expected vs actual behavior + - Contract state when the bug occurred + - Transaction hash (if applicable) + +### Suggesting Enhancements + +Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion: + +1. Use a clear and descriptive title +2. Provide detailed description of the proposed functionality +3. Explain why this enhancement would be useful +4. Consider security implications + +### Pull Requests + +1. Fork the repository +2. Create a new branch for your feature +3. Implement your changes +4. Write or update tests +5. Update documentation +6. Submit a pull request + +#### Pull Request Process + +1. Update the README.md with details of changes if applicable +2. Update the documentation +3. Add tests for new functionality +4. Ensure all tests pass +5. Get approval from maintainers + +## Development Workflow + +### Setting Up Development Environment + +1. Install Clarity CLI tools +2. Set up a local Stacks blockchain +3. Configure testing environment + +### Testing Guidelines + +- Write unit tests for all new functions +- Test edge cases and failure scenarios +- Include integration tests where applicable +- Maintain test coverage above 90% + +### Coding Standards + +- Follow Clarity best practices +- Use meaningful variable and function names +- Comment complex logic +- Keep functions focused and modular +- Add appropriate error handling + +### Documentation Standards + +- Document all public functions +- Include usage examples +- Update constant definitions +- Maintain clear error code documentation + +## Smart Contract Specifics + +### Making Changes to Core Functions + +1. Understand existing security measures +2. Consider backward compatibility +3. Document state changes +4. Add appropriate checks and balances + +### Adding New Features + +1. Ensure compatibility with existing functions +2. Follow established patterns +3. Consider gas optimization +4. Add appropriate events/logs + +## Review Process + +1. Technical review +2. Security review +3. Documentation review +4. Testing verification + +## Questions? + +Feel free to contact the maintainers or open an issue for clarification. + +Thank you for contributing! diff --git a/Clarinet.toml b/Clarinet.toml index a1c7168..acea7fd 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -1,20 +1,22 @@ - [project] name = "StacksFund" authors = [] +description = "" telemetry = true +requirements = [] +[contracts.stacksfund] +path = "contracts/stacksfund.clar" +depends_on = [] + +[repl] +costs_version = 2 +parser_version = 2 + [repl.analysis] passes = ["check_checker"] + [repl.analysis.check_checker] -# If true, inputs are trusted after tx_sender has been checked. +strict = false trusted_sender = false -# If true, inputs are trusted after contract-caller has been checked. trusted_caller = false -# 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. callee_filter = false - -# [contracts.counter] -# path = "contracts/counter.clar" -# depends_on = [] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b5d5f29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,37 @@ +# MIT License + +Copyright (c) 2024 Nicholas Ekpenyong + +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. + +## Additional Blockchain-Specific Terms + +1. **No Warranty for Smart Contract Operation**: The smart contract code is provided as-is, and no warranty is provided for its operation on any blockchain network. + +2. **Risk Acknowledgment**: Users acknowledge that interacting with smart contracts carries inherent risks, including but not limited to: + + - Potential loss of funds + - Smart contract vulnerabilities + - Network-related issues + - Front-running attacks + - Other blockchain-specific risks + +3. **No Financial Advice**: Nothing in this software constitutes financial advice. Users are responsible for their own financial decisions. + +4. **Regulatory Compliance**: Users are responsible for ensuring their use of this smart contract complies with their local regulations. diff --git a/README.md b/README.md new file mode 100644 index 0000000..518ee58 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# Stacks Fund Smart Contract + +## Overview + +The Stacks Fund Smart Contract is a decentralized fund management system built on the Stacks blockchain. It enables users to participate in collective fund management through a transparent and secure smart contract system. + +## Features + +- **Deposit Management**: Secure deposit of STX tokens with minimum deposit requirements +- **Token System**: Automatic minting and burning of fund tokens representing shares +- **Proposal System**: Create and vote on fund allocation proposals +- **Democratic Governance**: Token-weighted voting system for proposal decisions +- **Time-Locked Deposits**: Security mechanism to prevent rapid withdrawals +- **Automated Execution**: Secure execution of approved proposals + +## Core Functions + +### User Functions + +- `deposit`: Deposit STX tokens into the fund +- `withdraw`: Withdraw STX tokens after lock period +- `create-proposal`: Submit new fund allocation proposals +- `vote`: Participate in proposal voting +- `execute-proposal`: Execute approved proposals + +### Read-Only Functions + +- `get-balance`: Check account balance +- `get-total-supply`: View total token supply +- `get-proposal`: Retrieve proposal details +- `get-deposit-info`: View deposit information +- `get-vote`: Check voting records + +## Technical Details + +### Constants + +- Minimum deposit: 1,000,000 microSTX +- Lock period: ~10 days (1440 blocks) +- Minimum proposal duration: 1 day (144 blocks) +- Maximum proposal duration: 14 days (20,160 blocks) + +### Error Codes + +- `100`: Owner-only operation +- `101`: Contract not initialized +- `102`: Already initialized +- `103`: Insufficient balance +- `104`: Invalid amount +- (See contract for complete error code listing) + +## Getting Started + +### Prerequisites + +- Stacks wallet +- Minimum deposit amount in STX +- Understanding of smart contract interactions + +### Interacting with the Contract + +1. **Initialize Contract** (owner only) +2. **Make Deposit** + ```clarity + (contract-call? .stacks-fund deposit u1000000) + ``` +3. **Create Proposal** + ```clarity + (contract-call? .stacks-fund create-proposal "Proposal Description" u500000 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM u2880) + ``` + +## Security Considerations + +- Funds are time-locked after deposit +- Proposal execution requires majority approval +- Built-in checks for balance verification +- Contract owner privileges are limited + +## Development Status + +This contract is in production-ready state but should undergo thorough security audit before mainnet deployment. + +## Contributing + +Please see [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. + +## Security + +For security concerns, please review our [SECURITY.md](SECURITY.md) file. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..eb3da5a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,130 @@ +# Security Policy + +## Security Prerequisites + +- All interactions with this smart contract should be performed with full understanding of the risks involved in blockchain transactions +- Users should verify they are interacting with the correct contract address +- Private keys and wallet security are the responsibility of the users + +## Reporting a Vulnerability + +### Responsible Disclosure + +1. **DO NOT** create a public GitHub issue for security vulnerabilities +2. Email security concerns to nicholas4585@gmail.com +3. Include detailed information about the vulnerability +4. If possible, include a proof of concept +5. Allow reasonable time for response and patch development + +### Response Timeline + +- Initial Response: Within 24 hours +- Assessment: Within 72 hours +- Fix Development: Timeline provided based on severity +- Public Disclosure: After fix implementation and testing + +## Security Measures + +### Smart Contract Security + +1. **Time Locks** + + - Deposits are locked for ~10 days + - Prevents rapid withdrawal attacks + - Protects fund stability + +2. **Access Controls** + + - Owner-only initialization + - Validated proposal creation + - Token-weighted voting system + +3. **Balance Verification** + + - Strict balance checks + - Prevention of overflow/underflow + - Automated proposal execution checks + +4. **Error Handling** + - Comprehensive error codes + - Proper revert conditions + - Clear error messages + +### Known Limitations + +1. Block time dependency for time calculations +2. Transaction ordering constraints +3. Front-running possibilities in proposal voting + +## Best Practices for Users + +### Interacting with the Contract + +1. **Before Depositing** + + - Verify contract address + - Understand lock period + - Check minimum deposit requirements + +2. **When Voting** + + - Review proposal details thoroughly + - Understand voting power calculation + - Check proposal expiration + +3. **For Withdrawals** + - Verify lock period completion + - Ensure sufficient balance + - Check network conditions + +### Security Recommendations + +1. Use hardware wallets when possible +2. Never share private keys +3. Verify transaction details before signing +4. Keep software and wallets updated +5. Be aware of phishing attempts + +## Audit Status + +- Initial audit completed: [Date] +- Latest audit: [Date] +- Known issues: [Link to issues] +- Audit reports: [Link to reports] + +## Ongoing Security Measures + +1. Regular code reviews +2. Continuous monitoring +3. Community bug bounty program +4. Third-party security audits +5. Automated testing + +## Emergency Procedures + +### In Case of Breach + +1. Contact security team immediately +2. Follow responsible disclosure process +3. Do not attempt exploitation +4. Document all relevant information + +### Emergency Contacts + +- Security Team: [Contact Information] +- Development Team: [Contact Information] +- Community Managers: [Contact Information] + +## Updates and Patches + +- Security updates will be announced through official channels +- Emergency patches may be deployed with minimal notice +- All updates will be documented and explained + +## Compliance + +This security policy complies with: + +- Industry standard security practices +- Blockchain security best practices +- Smart contract development guidelines diff --git a/contracts/stacksfund.clar b/contracts/stacksfund.clar new file mode 100644 index 0000000..985d6df --- /dev/null +++ b/contracts/stacksfund.clar @@ -0,0 +1,289 @@ +;; Title +;; StacksFund Smart Contract + +;; Summary +;; A decentralized fund management contract on the Stacks blockchain, enabling users to deposit, withdraw, create proposals, and vote on them. + +;; Description +;; The StacksFund smart contract is designed to manage a decentralized fund on the Stacks blockchain. +;; It includes functionalities for depositing and withdrawing funds, creating and voting on proposals, and executing approved proposals. +;; The contract ensures security and proper fund management through various checks and balances. + +;; Constants +(define-constant contract-owner tx-sender) +(define-constant err-owner-only (err u100)) +(define-constant err-not-initialized (err u101)) +(define-constant err-already-initialized (err u102)) +(define-constant err-insufficient-balance (err u103)) +(define-constant err-invalid-amount (err u104)) +(define-constant err-unauthorized (err u105)) +(define-constant err-proposal-not-found (err u106)) +(define-constant err-proposal-expired (err u107)) +(define-constant err-already-voted (err u108)) +(define-constant err-below-minimum (err u109)) +(define-constant err-locked-period (err u110)) +(define-constant err-transfer-failed (err u111)) +(define-constant err-invalid-duration (err u112)) +(define-constant err-zero-amount (err u113)) +(define-constant err-invalid-target (err u114)) +(define-constant err-invalid-description (err u115)) +(define-constant err-invalid-proposal-id (err u116)) +(define-constant err-invalid-vote (err u117)) +(define-constant minimum-duration u144) ;; minimum 1 day (assuming 10min blocks) +(define-constant maximum-duration u20160) ;; maximum 14 days + +;; Data Variables +(define-data-var total-supply uint u0) +(define-data-var minimum-deposit uint u1000000) ;; in microSTX +(define-data-var lock-period uint u1440) ;; ~10 days in blocks +(define-data-var initialized bool false) +(define-data-var last-rebalance uint u0) +(define-data-var proposal-count uint u0) + +;; Data Maps +(define-map balances principal uint) +(define-map deposits + principal + { + amount: uint, + lock-until: uint, + last-reward-block: uint + } +) + +(define-map proposals + uint + { + proposer: principal, + description: (string-ascii 256), + amount: uint, + target: principal, + expires-at: uint, + executed: bool, + yes-votes: uint, + no-votes: uint + } +) + +(define-map votes {proposal-id: uint, voter: principal} bool) + +;; Private Functions +(define-private (is-contract-owner) + (is-eq tx-sender contract-owner) +) + +(define-private (check-initialized) + (ok (asserts! (var-get initialized) err-not-initialized)) +) + +(define-private (validate-proposal-id (proposal-id uint)) + (ok (asserts! (<= proposal-id (var-get proposal-count)) err-invalid-proposal-id)) +) + +(define-private (calculate-voting-power (voter principal)) + (default-to u0 (map-get? balances voter)) +) + +(define-private (transfer-tokens (sender principal) (recipient principal) (amount uint)) + (let ( + (sender-balance (default-to u0 (map-get? balances sender))) + (recipient-balance (default-to u0 (map-get? balances recipient))) + ) + (asserts! (>= sender-balance amount) err-insufficient-balance) + (map-set balances sender (- sender-balance amount)) + (map-set balances recipient (+ recipient-balance amount)) + (ok true) + ) +) + +(define-private (mint-tokens (account principal) (amount uint)) + (let ( + (current-balance (default-to u0 (map-get? balances account))) + ) + (map-set balances account (+ current-balance amount)) + (var-set total-supply (+ (var-get total-supply) amount)) + (ok true) + ) +) + +(define-private (burn-tokens (account principal) (amount uint)) + (let ( + (current-balance (default-to u0 (map-get? balances account))) + ) + (asserts! (>= current-balance amount) err-insufficient-balance) + (map-set balances account (- current-balance amount)) + (var-set total-supply (- (var-get total-supply) amount)) + (ok true) + ) +) + +;; Public Functions +(define-public (initialize) + (begin + (asserts! (is-contract-owner) err-owner-only) + (asserts! (not (var-get initialized)) err-already-initialized) + (var-set initialized true) + (ok true) + ) +) + +(define-public (deposit (amount uint)) + (begin + (try! (check-initialized)) + (asserts! (>= amount (var-get minimum-deposit)) err-below-minimum) + (asserts! (> amount u0) err-zero-amount) + + ;; Transfer STX to contract + (try! (stx-transfer? amount tx-sender (as-contract tx-sender))) + + ;; Update deposit records + (map-set deposits tx-sender { + amount: amount, + lock-until: (+ block-height (var-get lock-period)), + last-reward-block: block-height + }) + + ;; Mint fund tokens + (mint-tokens tx-sender amount) + ) +) + +(define-public (withdraw (amount uint)) + (begin + (try! (check-initialized)) + (asserts! (> amount u0) err-zero-amount) + + (let ( + (deposit-info (unwrap! (map-get? deposits tx-sender) err-unauthorized)) + (user-balance (unwrap! (get-balance tx-sender) err-unauthorized)) + ) + (asserts! (>= block-height (get lock-until deposit-info)) err-locked-period) + (asserts! (>= user-balance amount) err-insufficient-balance) + + ;; Burn tokens first + (try! (burn-tokens tx-sender amount)) + + ;; Transfer STX back to user + (as-contract (stx-transfer? amount (as-contract tx-sender) tx-sender)) + ) + ) +) + +(define-public (create-proposal + (description (string-ascii 256)) + (amount uint) + (target principal) + (duration uint) +) + (begin + (try! (check-initialized)) + + ;; Input validation + (asserts! (> (len description) u0) err-invalid-description) + (asserts! (> amount u0) err-zero-amount) + (asserts! (not (is-eq target (as-contract tx-sender))) err-invalid-target) + (asserts! (and (>= duration minimum-duration) (<= duration maximum-duration)) err-invalid-duration) + + (let ( + (proposer-balance (unwrap! (map-get? balances tx-sender) err-unauthorized)) + (proposal-id (+ (var-get proposal-count) u1)) + ) + (asserts! (> proposer-balance u0) err-unauthorized) + + ;; Create new proposal with validated inputs + (map-set proposals proposal-id { + proposer: tx-sender, + description: description, + amount: amount, + target: target, + expires-at: (+ block-height duration), + executed: false, + yes-votes: u0, + no-votes: u0 + }) + + (var-set proposal-count proposal-id) + (ok proposal-id) + ) + ) +) + +(define-public (vote (proposal-id uint) (vote-for bool)) + (begin + (try! (check-initialized)) + (try! (validate-proposal-id proposal-id)) + + (let ( + (proposal (unwrap! (map-get? proposals proposal-id) err-proposal-not-found)) + (voter-power (calculate-voting-power tx-sender)) + ) + (asserts! (> voter-power u0) err-unauthorized) + (asserts! (< block-height (get expires-at proposal)) err-proposal-expired) + (asserts! (is-none (map-get? votes {proposal-id: proposal-id, voter: tx-sender})) err-already-voted) + + ;; Record vote after all validations pass + (map-set votes {proposal-id: proposal-id, voter: tx-sender} vote-for) + + ;; Update vote counts + (map-set proposals proposal-id + (merge proposal + { + yes-votes: (if vote-for + (+ (get yes-votes proposal) voter-power) + (get yes-votes proposal)), + no-votes: (if vote-for + (get no-votes proposal) + (+ (get no-votes proposal) voter-power)) + } + ) + ) + + (ok true) + ) + ) +) + +(define-public (execute-proposal (proposal-id uint)) + (begin + (try! (check-initialized)) + (try! (validate-proposal-id proposal-id)) + + (let ( + (proposal (unwrap! (map-get? proposals proposal-id) err-proposal-not-found)) + (contract-balance (stx-get-balance (as-contract tx-sender))) + ) + (asserts! (not (get executed proposal)) err-unauthorized) + (asserts! (>= block-height (get expires-at proposal)) err-proposal-expired) + (asserts! (> (get yes-votes proposal) (get no-votes proposal)) err-unauthorized) + (asserts! (>= contract-balance (get amount proposal)) err-insufficient-balance) + + ;; Execute proposal (transfer funds) + (try! (as-contract (stx-transfer? (get amount proposal) (as-contract tx-sender) (get target proposal)))) + + ;; Mark proposal as executed + (map-set proposals proposal-id (merge proposal {executed: true})) + (ok true) + ) + ) +) + +;; Read-only functions +(define-read-only (get-balance (account principal)) + (ok (default-to u0 (map-get? balances account))) +) + +(define-read-only (get-total-supply) + (ok (var-get total-supply)) +) + +(define-read-only (get-proposal (proposal-id uint)) + (ok (map-get? proposals proposal-id)) +) + +(define-read-only (get-deposit-info (account principal)) + (ok (map-get? deposits account)) +) + +(define-read-only (get-vote (proposal-id uint) (voter principal)) + (ok (map-get? votes {proposal-id: proposal-id, voter: voter})) +) \ No newline at end of file diff --git a/tests/stacksfund_test.ts b/tests/stacksfund_test.ts new file mode 100644 index 0000000..9a18ae0 --- /dev/null +++ b/tests/stacksfund_test.ts @@ -0,0 +1,26 @@ + +import { Clarinet, Tx, Chain, Account, types } from 'https://deno.land/x/clarinet@v0.14.0/index.ts'; +import { assertEquals } from 'https://deno.land/std@0.90.0/testing/asserts.ts'; + +Clarinet.test({ + name: "Ensure that <...>", + async fn(chain: Chain, accounts: Map) { + let block = chain.mineBlock([ + /* + * Add transactions with: + * Tx.contractCall(...) + */ + ]); + assertEquals(block.receipts.length, 0); + assertEquals(block.height, 2); + + block = chain.mineBlock([ + /* + * Add transactions with: + * Tx.contractCall(...) + */ + ]); + assertEquals(block.receipts.length, 0); + assertEquals(block.height, 3); + }, +});