diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..5bff4ee --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,39 @@ +# Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible 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 + +Examples of behavior that contributes to a positive environment: + +- 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 + +Examples of 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 + +## Enforcement Responsibilities + +Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainers responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..921a90e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,53 @@ +# Contributing Guidelines + +Thank you for your interest in contributing to the Stablecoin Vault Contract! This document provides guidelines and instructions for contributing. + +## Development Process + +1. Fork the repository +2. Create a new branch for your feature/fix +3. Write tests for your changes +4. Implement your changes +5. Run tests and ensure they pass +6. Submit a pull request + +## Code Style Guidelines + +- Follow the Clarity style guide +- Use meaningful variable and function names +- Add comments for complex logic +- Keep functions focused and small +- Include proper error handling + +## Testing Requirements + +- Write unit tests for new functions +- Include integration tests for complex interactions +- Test edge cases and error conditions +- Ensure all tests pass before submitting PR + +## Security Considerations + +- Always validate input parameters +- Check for arithmetic overflow/underflow +- Implement proper access controls +- Follow the principle of least privilege +- Add relevant security tests + +## Pull Request Process + +1. Update documentation for any changes +2. Add tests for new functionality +3. Ensure CI passes +4. Request review from maintainers +5. Address review feedback + +## Getting Help + +- Open an issue for questions +- Join our community chat +- Read the technical documentation + +## Code Review Process + +All submissions require review. We use GitHub pull requests for this purpose. diff --git a/Clarinet.toml b/Clarinet.toml index a971368..f426cd9 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -1,20 +1,22 @@ - [project] name = "bitstable" authors = [] +description = "" telemetry = true +requirements = [] +[contracts.bitstable] +path = "contracts/bitstable.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/README.md b/README.md new file mode 100644 index 0000000..5296862 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# Stablecoin Vault Contract + +A decentralized stablecoin system built on Stacks that enables users to create collateralized debt positions (CDPs) using STX as collateral. + +## Overview + +The Stablecoin Vault Contract implements a decentralized stablecoin system where users can: + +- Create vaults by depositing STX as collateral +- Mint stablecoins against their collateral +- Manage their positions (repay debt, withdraw collateral) +- Get liquidated if their position falls below the liquidation ratio + +## Key Features + +- **Collateralized Debt Positions (CDPs)** + + - Minimum collateralization ratio: 150% + - Liquidation threshold: 120% + - Dynamic stability fee mechanism + +- **Price Oracle Integration** + + - Real-time collateral valuation + - Multiple oracle support + - Price validity checks + +- **Risk Management** + - Liquidation mechanism + - Emergency shutdown capability + - Governance controls for risk parameters + +## Quick Start + +1. Initialize the contract with a valid price: + +```clarity +(contract-call? .stablecoin-vault initialize u50000000) +``` + +2. Create a vault and deposit collateral: + +```clarity +(contract-call? .stablecoin-vault create-vault u1000000) +``` + +3. Mint stablecoins against your collateral: + +```clarity +(contract-call? .stablecoin-vault mint-stablecoin u500) +``` + +## Documentation + +- [Technical Specification](docs/technical-specification.md) +- [Security Policy](SECURITY.md) +- [Contributing Guidelines](CONTRIBUTING.md) +- [Code of Conduct](CODE_OF_CONDUCT.md) + +## Contract Parameters + +- Minimum Collateral Ratio: 150% +- Liquidation Ratio: 120% +- Stability Fee: 2% annual +- Maximum Price: 1,000,000,000 +- Minimum Price: 1 +- Maximum Ratio: 1000% +- Minimum Ratio: 101% +- Maximum Fee: 100% diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ff8c1d5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,59 @@ +# Security Policy + +## Reporting a Vulnerability + +If you discover a security vulnerability in the Stablecoin Vault Contract, please follow these steps: + +1. **Do NOT disclose the vulnerability publicly** +2. Email the security team at timileyincreate4@gmail.com +3. Include detailed information about the vulnerability +4. Provide steps to reproduce if possible + +## Security Measures + +The contract implements several security measures: + +### Access Controls + +- Owner-only functions for critical operations +- Role-based access for oracles and liquidators +- Emergency shutdown capability + +### Price Safety + +- Valid price range checks +- Multiple oracle support +- Price staleness checks + +### Collateral Management + +- Minimum collateralization ratio +- Liquidation threshold +- Safe math operations + +### System Parameters + +- Maximum and minimum bounds for all parameters +- Governance controls for parameter updates +- Emergency shutdown mechanism + +## Security Considerations + +When using the contract: + +1. **Price Oracle** + + - Ensure multiple reliable oracles + - Implement price validity checks + - Monitor for price manipulation + +2. **Collateral Management** + + - Maintain healthy collateralization ratio + - Monitor liquidation risk + - Understand stability fee implications + +3. **System Parameters** + - Review parameter changes + - Understand impact on positions + - Monitor governance decisions diff --git a/contracts/bitstable.clar b/contracts/bitstable.clar new file mode 100644 index 0000000..7d742d2 --- /dev/null +++ b/contracts/bitstable.clar @@ -0,0 +1,339 @@ +;; Title: Stablecoin Vault Contract + +;; Summary: A collateralized debt position (CDP) system for minting stablecoins against STX collateral + +;; Description: This contract implements a decentralized stablecoin system where users can: +;; - Create vaults by depositing STX as collateral +;; - Mint stablecoins against their collateral maintaining a minimum collateral ratio +;; - Manage their positions (repay debt, withdraw collateral) +;; - Get liquidated if their position falls below the liquidation ratio +;; The system includes: +;; - Price oracle integration for real-time collateral valuation +;; - Liquidation mechanism to ensure system solvency +;; - Governance controls for risk parameters +;; - Emergency shutdown capability +;; - Stability fee mechanism for system sustainability + +;; Constants +(define-constant contract-owner tx-sender) +(define-constant err-owner-only (err u100)) +(define-constant err-insufficient-collateral (err u101)) +(define-constant err-below-mcr (err u102)) +(define-constant err-already-initialized (err u103)) +(define-constant err-not-initialized (err u104)) +(define-constant err-low-balance (err u105)) +(define-constant err-invalid-price (err u106)) +(define-constant err-emergency-shutdown (err u107)) +(define-constant err-invalid-parameter (err u108)) +(define-constant maximum-price u1000000000) ;; Maximum allowed price (sanity check) +(define-constant minimum-price u1) ;; Minimum allowed price +(define-constant maximum-ratio u1000) ;; Maximum collateral ratio (1000%) +(define-constant minimum-ratio u101) ;; Minimum collateral ratio (101%) +(define-constant maximum-fee u100) ;; Maximum stability fee (100%) + +;; Data Variables +(define-data-var minimum-collateral-ratio uint u150) ;; 150% collateralization ratio +(define-data-var liquidation-ratio uint u120) ;; 120% liquidation threshold +(define-data-var stability-fee uint u2) ;; 2% annual stability fee +(define-data-var initialized bool false) +(define-data-var emergency-shutdown bool false) +(define-data-var last-price uint u0) ;; Latest BTC/USD price +(define-data-var price-valid bool false) +(define-data-var governance-token principal 'SP000000000000000000002Q6VF78.governance-token) + +;; Storage +(define-map vaults + principal + { + collateral: uint, + debt: uint, + last-fee-timestamp: uint + } +) + +(define-map liquidators principal bool) +(define-map price-oracles principal bool) + +;; Validation Functions +(define-private (is-valid-price (price uint)) + (and + (>= price minimum-price) + (<= price maximum-price) + ) +) + +(define-private (is-valid-ratio (ratio uint)) + (and + (>= ratio minimum-ratio) + (<= ratio maximum-ratio) + ) +) + +(define-private (is-valid-fee (fee uint)) + (<= fee maximum-fee) +) + +;; Public Functions +(define-public (initialize (btc-price uint)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (not (var-get initialized)) err-already-initialized) + (asserts! (is-valid-price btc-price) err-invalid-parameter) + (var-set last-price btc-price) + (var-set price-valid true) + (var-set initialized true) + (ok true) + ) +) + +(define-public (create-vault (collateral-amount uint)) + (let ( + (existing-vault (default-to + { + collateral: u0, + debt: u0, + last-fee-timestamp: (unwrap-panic (get-block-info? time u0)) + } + (map-get? vaults tx-sender) + )) + ) + (begin + (asserts! (var-get initialized) err-not-initialized) + (asserts! (not (var-get emergency-shutdown)) err-emergency-shutdown) + (try! (stx-transfer? collateral-amount tx-sender (as-contract tx-sender))) + (map-set vaults tx-sender + (merge existing-vault { + collateral: (+ collateral-amount (get collateral existing-vault)) + }) + ) + (ok true) + )) +) + +(define-public (mint-stablecoin (amount uint)) + (let ( + (vault (unwrap! (map-get? vaults tx-sender) err-low-balance)) + (current-collateral (get collateral vault)) + (current-debt (get debt vault)) + (new-debt (+ current-debt amount)) + (collateral-value (* current-collateral (var-get last-price))) + ) + (begin + (asserts! (var-get initialized) err-not-initialized) + (asserts! (not (var-get emergency-shutdown)) err-emergency-shutdown) + (asserts! (var-get price-valid) err-invalid-price) + ;; Check if new debt maintains minimum collateral ratio + (asserts! (>= (* collateral-value u100) + (* new-debt (var-get minimum-collateral-ratio))) + err-below-mcr) + (map-set vaults tx-sender + (merge vault { + debt: new-debt + }) + ) + (ok true) + )) +) + +(define-public (repay-debt (amount uint)) + (let ( + (vault (unwrap! (map-get? vaults tx-sender) err-low-balance)) + (current-debt (get debt vault)) + ) + (begin + (asserts! (var-get initialized) err-not-initialized) + (asserts! (>= current-debt amount) err-low-balance) + (map-set vaults tx-sender + (merge vault { + debt: (- current-debt amount) + }) + ) + (ok true) + )) +) + +(define-public (withdraw-collateral (amount uint)) + (let ( + (vault (unwrap! (map-get? vaults tx-sender) err-low-balance)) + (current-collateral (get collateral vault)) + (current-debt (get debt vault)) + (new-collateral (- current-collateral amount)) + (collateral-value (* new-collateral (var-get last-price))) + ) + (begin + (asserts! (var-get initialized) err-not-initialized) + (asserts! (not (var-get emergency-shutdown)) err-emergency-shutdown) + (asserts! (var-get price-valid) err-invalid-price) + (asserts! (>= current-collateral amount) err-low-balance) + ;; Check if withdrawal maintains minimum collateral ratio + (asserts! (or + (is-eq current-debt u0) + (>= (* collateral-value u100) + (* current-debt (var-get minimum-collateral-ratio)))) + err-below-mcr) + (try! (as-contract (stx-transfer? amount (as-contract tx-sender) tx-sender))) + (map-set vaults tx-sender + (merge vault { + collateral: new-collateral + }) + ) + (ok true) + )) +) + +;; Liquidation Functions +(define-public (liquidate (vault-owner principal)) + (let ( + (vault (unwrap! (map-get? vaults vault-owner) err-low-balance)) + (collateral (get collateral vault)) + (debt (get debt vault)) + (collateral-value (* collateral (var-get last-price))) + ) + (begin + ;; Basic checks + (asserts! (var-get initialized) err-not-initialized) + (asserts! (var-get price-valid) err-invalid-price) + (asserts! (is-authorized-liquidator tx-sender) err-owner-only) + + ;; Ensure vault exists and has debt + (asserts! (> debt u0) err-invalid-parameter) + + ;; Check if vault is below liquidation ratio + (asserts! (< (* collateral-value u100) + (* debt (var-get liquidation-ratio))) + err-insufficient-collateral) + + ;; Save collateral locally to ensure consistency + (let ( + (collateral-to-transfer collateral) + ) + ;; Clear vault first to prevent reentrancy + (map-delete vaults vault-owner) + ;; Transfer collateral to liquidator + (try! (as-contract (stx-transfer? collateral-to-transfer (as-contract tx-sender) tx-sender))) + (ok true) + ) + )) +) + +;; Oracle Functions +(define-public (update-price (new-price uint)) + (begin + (asserts! (is-authorized-oracle tx-sender) err-owner-only) + (asserts! (is-valid-price new-price) err-invalid-parameter) + (var-set last-price new-price) + (var-set price-valid true) + (ok true) + ) +) + +;; Governance Functions +(define-public (set-minimum-collateral-ratio (new-ratio uint)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (is-valid-ratio new-ratio) err-invalid-parameter) + (asserts! (> new-ratio (var-get liquidation-ratio)) err-invalid-parameter) + (var-set minimum-collateral-ratio new-ratio) + (ok true) + ) +) + +(define-public (set-liquidation-ratio (new-ratio uint)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (is-valid-ratio new-ratio) err-invalid-parameter) + (asserts! (< new-ratio (var-get minimum-collateral-ratio)) err-invalid-parameter) + (var-set liquidation-ratio new-ratio) + (ok true) + ) +) + +(define-public (set-stability-fee (new-fee uint)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (is-valid-fee new-fee) err-invalid-parameter) + (var-set stability-fee new-fee) + (ok true) + ) +) + +(define-public (add-liquidator (liquidator principal)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (not (is-authorized-liquidator liquidator)) err-invalid-parameter) + (map-set liquidators liquidator true) + (ok true) + ) +) + +(define-public (remove-liquidator (liquidator principal)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (is-authorized-liquidator liquidator) err-invalid-parameter) + (map-delete liquidators liquidator) + (ok true) + ) +) + +(define-public (add-oracle (oracle principal)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (not (is-authorized-oracle oracle)) err-invalid-parameter) + (map-set price-oracles oracle true) + (ok true) + ) +) + +(define-public (remove-oracle (oracle principal)) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (asserts! (is-authorized-oracle oracle) err-invalid-parameter) + (map-delete price-oracles oracle) + (ok true) + ) +) + +;; Emergency Functions +(define-public (trigger-emergency-shutdown) + (begin + (asserts! (is-eq tx-sender contract-owner) err-owner-only) + (var-set emergency-shutdown true) + (ok true) + ) +) + +;; Read-Only Functions +(define-read-only (get-vault (owner principal)) + (map-get? vaults owner) +) + +(define-read-only (get-collateral-ratio (owner principal)) + (let ( + (vault (unwrap! (map-get? vaults owner) err-low-balance)) + (collateral (get collateral vault)) + (debt (get debt vault)) + ) + (if (is-eq debt u0) + (ok u0) + (ok (/ (* collateral (var-get last-price)) debt)) + )) +) + +(define-read-only (is-authorized-liquidator (address principal)) + (default-to false (map-get? liquidators address)) +) + +(define-read-only (is-authorized-oracle (address principal)) + (default-to false (map-get? price-oracles address)) +) + +(define-read-only (get-stability-parameters) + { + minimum-collateral-ratio: (var-get minimum-collateral-ratio), + liquidation-ratio: (var-get liquidation-ratio), + stability-fee: (var-get stability-fee), + price: (var-get last-price), + price-valid: (var-get price-valid), + emergency-shutdown: (var-get emergency-shutdown) + } +) \ No newline at end of file diff --git a/docs/technical-specification.md b/docs/technical-specification.md new file mode 100644 index 0000000..186bb4f --- /dev/null +++ b/docs/technical-specification.md @@ -0,0 +1,178 @@ +# Technical Specification + +## System Overview + +The Stablecoin Vault Contract implements a collateralized debt position (CDP) system allowing users to mint stablecoins against STX collateral. + +## Core Components + +### 1. Vault Management + +#### Vault Structure + +```clarity +{ + collateral: uint, + debt: uint, + last-fee-timestamp: uint +} +``` + +#### Key Operations + +- Create vault +- Deposit collateral +- Mint stablecoins +- Repay debt +- Withdraw collateral + +### 2. Risk Parameters + +#### Collateral Requirements + +- Minimum Collateral Ratio: 150% +- Liquidation Ratio: 120% +- Stability Fee: 2% annual + +#### Price Management + +- Maximum Price: 1,000,000,000 +- Minimum Price: 1 +- Oracle validation + +### 3. Liquidation Mechanism + +#### Process + +1. Monitor collateral ratio +2. Trigger liquidation below threshold +3. Transfer collateral to liquidator +4. Clear vault debt + +#### Requirements + +- Authorized liquidators +- Valid price feed +- Below liquidation ratio + +### 4. Oracle System + +#### Features + +- Multiple oracle support +- Price validation +- Update permissions + +#### Price Requirements + +- Within valid range +- Recent timestamp +- Multiple confirmations + +### 5. Governance Controls + +#### Manageable Parameters + +- Collateral ratios +- Stability fee +- Oracle permissions +- Liquidator permissions + +#### Emergency Controls + +- System shutdown +- Parameter bounds +- Access controls + +## Technical Implementation + +### Core Functions + +#### Vault Creation + +```clarity +(define-public (create-vault (collateral-amount uint)) +``` + +Creates new vault with initial collateral + +#### Minting + +```clarity +(define-public (mint-stablecoin (amount uint)) +``` + +Mints stablecoins against collateral + +#### Liquidation + +```clarity +(define-public (liquidate (vault-owner principal)) +``` + +Processes vault liquidation + +### Error Handling + +#### Error Codes + +- 100: Owner only +- 101: Insufficient collateral +- 102: Below MCR +- 103: Already initialized +- 104: Not initialized +- 105: Low balance +- 106: Invalid price +- 107: Emergency shutdown +- 108: Invalid parameter + +### Security Measures + +#### Access Control + +- Owner functions +- Role-based permissions +- Emergency shutdown + +#### Validation + +- Parameter bounds +- Price checks +- Ratio requirements + +## Integration Guide + +### Contract Initialization + +```clarity +(contract-call? .stablecoin-vault initialize ) +``` + +### Creating a Vault + +```clarity +(contract-call? .stablecoin-vault create-vault ) +``` + +### Managing Positions + +```clarity +(contract-call? .stablecoin-vault mint-stablecoin ) +(contract-call? .stablecoin-vault repay-debt ) +(contract-call? .stablecoin-vault withdraw-collateral ) +``` + +## System Constraints + +### Limitations + +- Single collateral type (STX) +- Fixed stability fee +- Binary liquidation + +### Future Improvements + +- Multi-collateral support +- Variable stability fees +- Partial liquidations +- Auction mechanism diff --git a/tests/bitstable_test.ts b/tests/bitstable_test.ts new file mode 100644 index 0000000..9a18ae0 --- /dev/null +++ b/tests/bitstable_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); + }, +});