diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 460619f1..0af678be 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -20,35 +20,44 @@ jobs:
name: Foundry project
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - name: Check-out the repo
+ uses: actions/checkout@v3
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- with:
- version: nightly
+ - name: Debug Info
+ run: |
+ pwd
+ ls -la
+ cat foundry.toml
+
+ - name: Install dependencies
+ run: |
+ # Install OpenZeppelin contracts version 5.3.0
+ forge install OpenZeppelin/openzeppelin-contracts@v5.3.0
+ ls -la lib/
+
- name: Run Forge build
run: |
- forge --version
+ forge remappings
forge build --sizes
id: build
- name: Run Forge tests
- run: |
- forge test -vvv
+ run: forge test -vvv
id: test
- name: Run gas report
- run: |
- forge test --gas-report > gas-report.txt
+ run: forge test --gas-report > gas-report.txt
if: always()
id: gas
- name: Archive gas report
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: gas-report
- path: gas-report.txt
\ No newline at end of file
+ path: gas-report.txt
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..58d55b4c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,133 @@
+
+# Contributor Covenant 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, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders 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.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official email address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+[INSERT CONTACT METHOD].
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders 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 or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..be7c9644
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,197 @@
+# Contributing to CC Protocol
+
+Thank you for your interest in contributing to the Creative Crowdfunding Protocol! This document provides detailed guidelines to help you contribute effectively.
+
+## Table of Contents
+
+- [Code of Conduct](#code-of-conduct)
+- [Getting Started](#getting-started)
+ - [Issues](#issues)
+ - [Development Environment](#development-environment)
+- [Development Workflow](#development-workflow)
+ - [Branching Strategy](#branching-strategy)
+ - [Making Changes](#making-changes)
+ - [Testing](#testing)
+ - [Documentation](#documentation)
+- [Smart Contract Development Guidelines](#smart-contract-development-guidelines)
+ - [Security Best Practices](#security-best-practices)
+ - [Gas Optimization](#gas-optimization)
+ - [Code Style](#code-style)
+- [Pull Request Process](#pull-request-process)
+ - [PR Requirements](#pr-requirements)
+ - [Review Process](#review-process)
+- [Community](#community)
+
+## Code of Conduct
+
+Please read our [Code of Conduct](./CODE_OF_CONDUCT.md) to understand the behavior we expect from all contributors.
+
+## Getting Started
+
+### Issues
+
+#### Create a New Issue
+
+If you want to add or modify the content of this project:
+
+1. [Search if an issue already exists](https://github.com/ccprotocol/ccprotocol-contracts/issues)
+2. If a related issue doesn't exist, create a new issue using the appropriate template
+3. Discuss the proposed changes with the community before starting work
+4. Wait for issue assignment or approval before submitting a PR
+
+#### Solve an Issue
+
+Scan through our [existing issues](https://github.com/ccprotocol/ccprotocol-contracts/issues) to find one that interests you. You can use labels to filter issues:
+
+- `good first issue`: Suitable for newcomers
+- `bug`: Issues with the existing code
+- `enhancement`: New features or improvements
+- `documentation`: Documentation improvements
+- `help wanted`: Issues where help is particularly needed
+
+### Development Environment
+
+1. Fork the repository
+2. Clone your fork:
+ ```bash
+ git clone https://github.com/YOUR_USERNAME/ccprotocol-contracts.git
+ cd ccprotocol-contracts
+ ```
+3. Add the original repository as upstream:
+ ```bash
+ git remote add upstream https://github.com/ccprotocol/ccprotocol-contracts.git
+ ```
+4. Install development dependencies:
+ ```bash
+ forge install
+ ```
+5. Copy and configure environment variables:
+ ```bash
+ cp .env.example .env
+ # Edit .env with your settings
+ ```
+
+## Development Workflow
+
+### Branching Strategy
+
+- `main`: Production-ready code
+- `develop`: Integration branch for features
+- Feature branches: Named as `feature/your-feature-name`
+- Bug fix branches: Named as `fix/bug-name`
+
+Always create your working branch from `develop`:
+
+```bash
+git checkout develop
+git pull upstream develop
+git checkout -b feature/your-feature-name
+```
+
+### Making Changes
+
+1. Ensure your changes address a specific issue
+2. Make commits with clear, descriptive messages
+3. Keep changes focused and atomic
+4. Rebase your branch regularly to incorporate upstream changes:
+ ```bash
+ git fetch upstream
+ git rebase upstream/develop
+ ```
+
+### Testing
+
+All code changes must include appropriate tests:
+
+1. Write unit tests for new functionality
+2. Run the test suite to ensure all tests pass:
+ ```bash
+ forge test
+ ```
+3. For more detailed test output:
+ ```bash
+ forge test -vvv
+ ```
+4. Run gas reports to ensure efficiency:
+ ```bash
+ forge test --gas-report
+ ```
+
+### Documentation
+
+1. Update or add NatSpec comments for all public functions:
+ ```solidity
+ /**
+ * @notice Brief explanation of the function
+ * @param paramName Description of the parameter
+ * @return Description of the return value
+ */
+ function exampleFunction(uint256 paramName) public returns (bool) {
+ // Function implementation
+ }
+ ```
+2. Update relevant documentation in the `docs/` directory
+3. Include a summary of documentation changes in your PR
+
+## Smart Contract Development Guidelines
+
+### Security Best Practices
+
+1. Follow established security patterns
+2. Use OpenZeppelin contracts where appropriate
+3. Be aware of common vulnerabilities (reentrancy, frontrunning, etc.)
+4. Avoid complex control flows that are difficult to audit
+5. Consider formal verification for critical functions
+
+### Gas Optimization
+
+1. Be mindful of storage vs. memory usage
+2. Batch operations when possible
+3. Use appropriate data types (uint256 is often most gas-efficient)
+4. Consider gas costs in loops and data structures
+5. Include gas reports in PRs for significant changes
+
+### Code Style
+
+1. Follow Solidity style guides
+2. Use meaningful variable and function names
+3. Format your code using the prettier
+4. Keep functions small and focused
+5. Use appropriate visibility modifiers (public, external, internal, private)
+
+## Pull Request Process
+
+1. Update the README or documentation if needed
+2. Ensure all CI checks pass
+3. Create a pull request to the `develop` branch
+4. Fill in the PR template with all required information
+5. Request review from relevant team members
+
+### PR Requirements
+
+- PR title should be descriptive and reference the issue (e.g., "Fix #123: Add timestamp validation")
+- All tests must pass
+- Code must be properly formatted
+- New code should be covered by tests
+- Changes should be well-documented
+- Commit history should be clean and logical
+
+### Review Process
+
+1. At least one core contributor must review and approve the changes
+2. Address all review comments promptly
+3. CI checks must pass
+4. Changes may require revision based on feedback
+5. Once approved, a maintainer will merge the PR
+
+## Community
+
+- **GitHub Issues**: For bugs and feature requests
+- **Discord**: For quick questions and community discussions
+- **Pull Requests**: For code review discussions
+
+Join our community on [Discord](https://discord.gg/4tR9rWc3QE).
+
+## License
+
+By contributing to CC Protocol, you agree that your contributions will be licensed under the project's [MIT License](./LICENSE).
diff --git a/README.md b/README.md
index 79080955..68de14d6 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,6 @@ CC Protocol is a decentralized crowdfunding protocol designed to help creators l
- [Foundry](https://book.getfoundry.sh/)
- Solidity ^0.8.20
-- Node.js (recommended)
## Installation
@@ -38,11 +37,7 @@ forge install
cp .env.example .env
```
-4. Configure your `.env` file with:
-
-- Private key
-- RPC URL
-- (Optional) Contract addresses for reuse
+4. Configure your `.env` file following the template in `.env.example`
## Documentation
@@ -56,7 +51,6 @@ Comprehensive documentation is available in the `docs/` folder:
To view the documentation:
```bash
-# Navigate to docs folder
cd docs
```
@@ -93,18 +87,17 @@ anvil
forge script script/DeployAll.s.sol:DeployAll --rpc-url http://localhost:8545 --private-key $PRIVATE_KEY --broadcast
```
-#### Testnet Deployment
+#### Network Deployment
```bash
-# Deploy to testnet
-forge script script/DeployAll.s.sol:DeployAll --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast -vvvv
+# Deploy to any configured network
+forge script script/DeployAll.s.sol:DeployAll --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast
```
## Contract Architecture
### Core Contracts
-- `TestUSD`: Mock ERC20 token for testing
- `GlobalParams`: Protocol-wide parameter management
- `CampaignInfoFactory`: Campaign creation and management
- `TreasuryFactory`: Treasury contract deployment
@@ -113,28 +106,66 @@ forge script script/DeployAll.s.sol:DeployAll --rpc-url $RPC_URL --private-key $
- `AllOrNothing`: Funds refunded if campaign goal not met
+### Notes on Mock Contracts
+
+- `TestToken` is a mock ERC20 token used **only for testing and development purposes**.
+- It is located in the `mocks/` directory and should **not be included in production deployments**.
+
## Deployment Workflow
-1. Deploy `TestUSD`
-2. Deploy `GlobalParams`
-3. Deploy `TreasuryFactory`
-4. Deploy `CampaignInfoFactory`
+1. Deploy `GlobalParams`
+2. Deploy `TreasuryFactory`
+3. Deploy `CampaignInfoFactory`
+
+> For local testing or development, the `TestToken` mock token needs to be deployed before interacting with contracts requiring an ERC20 token.
## Environment Variables
-Key environment variables in `.env`:
+Key environment variables to configure in `.env`:
- `PRIVATE_KEY`: Deployment wallet private key
-- `RPC_URL`: Network RPC endpoint
+- `RPC_URL`: Network RPC endpoint (can be configured for any network)
- `SIMULATE`: Toggle simulation mode
- Contract address variables for reuse
-## Troubleshooting
+For a complete list of variables, refer to `.env.example`.
+
+## Security
+
+### Audits
+
+Security audit reports can be found in the [`audits/`](./audits/) folder. We regularly conduct security audits to ensure the safety and reliability of the protocol.
+
+## Contributing
+
+We welcome all contributions to the Creative Crowdfunding Protocol. If you're interested in helping, here's how you can contribute:
+
+- **Report bugs** by opening issues
+- **Suggest enhancements** or new features
+- **Submit pull requests** to improve the codebase
+- **Improve documentation** to make the project more accessible
+
+Before contributing, please read our detailed [Contributing Guidelines](./CONTRIBUTING.md) for comprehensive information on:
+- Development workflow
+- Coding standards
+- Testing requirements
+- Pull request process
+- Smart contract security considerations
+
+### Community
+
+Join our community on [Discord](https://discord.gg/4tR9rWc3QE) for questions and discussions.
+
+Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectful.
+
+## Contributors
+
+
+
+
-- Ensure sufficient network gas tokens
-- Verify RPC URL connectivity
-- Check contract dependencies
+Made with [contrib.rocks](https://contrib.rocks).
## License
-[SPDX-License-Identifier: UNLICENSED]
+This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).
\ No newline at end of file
diff --git a/audits/PeckShield-Audit-Report-CreativeCrowdfunding_v1.0.pdf b/audits/PeckShield-Audit-Report-CreativeCrowdfunding_v1.0.pdf
new file mode 100644
index 00000000..d301a934
Binary files /dev/null and b/audits/PeckShield-Audit-Report-CreativeCrowdfunding_v1.0.pdf differ
diff --git a/docs/book.toml b/docs/book.toml
index b93f4313..d8a41741 100644
--- a/docs/book.toml
+++ b/docs/book.toml
@@ -7,7 +7,7 @@ no-section-label = true
additional-js = ["solidity.min.js"]
additional-css = ["book.css"]
mathjax-support = true
-git-repository-url = "https://github.com/ccprotocol/reference-client-sc"
+git-repository-url = "https://github.com/ccprotocol/ccprotocol-contracts"
[output.html.fold]
enable = true
diff --git a/docs/src/README.md b/docs/src/README.md
index a5e70a42..68de14d6 100644
--- a/docs/src/README.md
+++ b/docs/src/README.md
@@ -1,67 +1,171 @@
-# CCP Contracts
-This repository contains the smart contracts source code and campaign configuration for Creative Crowdfunding Protocol - CCP. The repository uses Foundry as development environment for compilation, testing and deployment tasks.
+# Creative Crowdfunding Protocol (CC Protocol) Smart Contracts
-## What is CCP?
-CCP is a protocol for crowdfunding campaigns that allows creators to multilist campaigns across different crowdfunding platforms. It provides infrastructure tooling and support for platforms to create and manage campaigns in web3.
+## Overview
-## Documentation
-The detailed technical documentation for the protocol can be found in the [docs](./docs/src/SUMMARY.md) folder.
+CC Protocol is a decentralized crowdfunding protocol designed to help creators launch and manage campaigns across multiple platforms. By providing a standardized infrastructure, the protocol simplifies the process of creating, funding, and managing crowdfunding initiatives in web3 across different platforms.
+
+## Features
+
+- Cross-listable campaign creation
+- Multiple treasury models
+- Secure fund management
+- Customizable protocol parameters
-## Getting Started
-### Prerequisites
-The following tools are required to be installed in your system:
-- [Foundry](https://book.getfoundry.sh/getting-started/installation)
-- [Node.js](https://nodejs.org/en/download/)
+## Prerequisites
-### Installation
+- [Foundry](https://book.getfoundry.sh/)
+- Solidity ^0.8.20
-```shell
-$ npm install
+## Installation
+
+1. Clone the repository:
+
+```bash
+git clone https://github.com/ccprotocol/ccprotocol-contracts.git
+cd ccprotocol-contracts
```
-### Build
+2. Install dependencies:
-```shell
-$ forge build
+```bash
+forge install
```
-### Test
+3. Copy environment template:
+
+```bash
+cp .env.example .env
+```
+
+4. Configure your `.env` file following the template in `.env.example`
+
+## Documentation
+
+Comprehensive documentation is available in the `docs/` folder:
-```shell
-$ forge test
+- Technical specifications
+- Contract interfaces
+- Deployment guides
+- Development setup instructions
+
+To view the documentation:
+
+```bash
+cd docs
```
-### Format
+## Development
+
+### Compile Contracts
-```shell
-$ forge fmt
+```bash
+forge build
```
-### Gas Snapshots
+### Run Tests
-```shell
-$ forge snapshot
+```bash
+# Run all tests
+forge test
+
+# Run specific test
+forge test --match-test testFunctionName
+
+# Run tests with more verbose output
+forge test -vvv
```
-## Deploy
-### Environment Variables
+### Deploy Contracts
+
+#### Local Deployment
-Create an environment file named `.env`, fill the environment variables following the `.env.example` file and source the file using the following command:
+```bash
+# Start local blockchain
+anvil
-```shell
-$ source .env
+# Deploy to local network
+forge script script/DeployAll.s.sol:DeployAll --rpc-url http://localhost:8545 --private-key $PRIVATE_KEY --broadcast
```
-### Local Deployment
-To deploy the contracts locally, run the following command:
+#### Network Deployment
-```shell
-$ forge script script/Setup.s.sol:SetupScript
+```bash
+# Deploy to any configured network
+forge script script/DeployAll.s.sol:DeployAll --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast
```
-### Remote Deployment
-To deploy the contracts to a remote network, run the following command:
+## Contract Architecture
+
+### Core Contracts
+
+- `GlobalParams`: Protocol-wide parameter management
+- `CampaignInfoFactory`: Campaign creation and management
+- `TreasuryFactory`: Treasury contract deployment
+
+### Treasury Models
+
+- `AllOrNothing`: Funds refunded if campaign goal not met
+
+### Notes on Mock Contracts
+
+- `TestToken` is a mock ERC20 token used **only for testing and development purposes**.
+- It is located in the `mocks/` directory and should **not be included in production deployments**.
+
+## Deployment Workflow
+
+1. Deploy `GlobalParams`
+2. Deploy `TreasuryFactory`
+3. Deploy `CampaignInfoFactory`
+
+> For local testing or development, the `TestToken` mock token needs to be deployed before interacting with contracts requiring an ERC20 token.
+
+## Environment Variables
+
+Key environment variables to configure in `.env`:
+
+- `PRIVATE_KEY`: Deployment wallet private key
+- `RPC_URL`: Network RPC endpoint (can be configured for any network)
+- `SIMULATE`: Toggle simulation mode
+- Contract address variables for reuse
+
+For a complete list of variables, refer to `.env.example`.
+
+## Security
+
+### Audits
+
+Security audit reports can be found in the [`audits/`](./audits/) folder. We regularly conduct security audits to ensure the safety and reliability of the protocol.
+
+## Contributing
+
+We welcome all contributions to the Creative Crowdfunding Protocol. If you're interested in helping, here's how you can contribute:
+
+- **Report bugs** by opening issues
+- **Suggest enhancements** or new features
+- **Submit pull requests** to improve the codebase
+- **Improve documentation** to make the project more accessible
+
+Before contributing, please read our detailed [Contributing Guidelines](./CONTRIBUTING.md) for comprehensive information on:
+- Development workflow
+- Coding standards
+- Testing requirements
+- Pull request process
+- Smart contract security considerations
+
+### Community
+
+Join our community on [Discord](https://discord.gg/4tR9rWc3QE) for questions and discussions.
+
+Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectful.
+
+## Contributors
+
+
+
+
+
+Made with [contrib.rocks](https://contrib.rocks).
+
+## License
-```shell
-$ forge script script/Setup.s.sol:SetupScript --rpc-url $RPC_URL --private-key $PRIVATE_KEY
-```
\ No newline at end of file
+This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).
\ No newline at end of file
diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
index ca711d33..aafa9997 100644
--- a/docs/src/SUMMARY.md
+++ b/docs/src/SUMMARY.md
@@ -13,7 +13,6 @@
- [❱ treasuries](src/treasuries/README.md)
- [AllOrNothing](src/treasuries/AllOrNothing.sol/contract.AllOrNothing.md)
- [❱ utils](src/utils/README.md)
- - [AddressCalculator](src/utils/AddressCalculator.sol/library.AddressCalculator.md)
- [AdminAccessChecker](src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md)
- [BaseTreasury](src/utils/BaseTreasury.sol/abstract.BaseTreasury.md)
- [CampaignAccessChecker](src/utils/CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md)
@@ -25,5 +24,4 @@
- [CampaignInfo](src/CampaignInfo.sol/contract.CampaignInfo.md)
- [CampaignInfoFactory](src/CampaignInfoFactory.sol/contract.CampaignInfoFactory.md)
- [GlobalParams](src/GlobalParams.sol/contract.GlobalParams.md)
- - [TestUSD](src/TestUSD.sol/contract.TestUSD.md)
- [TreasuryFactory](src/TreasuryFactory.sol/contract.TreasuryFactory.md)
diff --git a/docs/src/src/CampaignInfo.sol/contract.CampaignInfo.md b/docs/src/src/CampaignInfo.sol/contract.CampaignInfo.md
index dfb8fae7..3543572d 100644
--- a/docs/src/src/CampaignInfo.sol/contract.CampaignInfo.md
+++ b/docs/src/src/CampaignInfo.sol/contract.CampaignInfo.md
@@ -1,5 +1,5 @@
# CampaignInfo
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/CampaignInfo.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/CampaignInfo.sol)
**Inherits:**
[ICampaignData](/src/interfaces/ICampaignData.sol/interface.ICampaignData.md), [ICampaignInfo](/src/interfaces/ICampaignInfo.sol/interface.ICampaignInfo.md), Ownable, [PausableCancellable](/src/utils/PausableCancellable.sol/abstract.PausableCancellable.md), [TimestampChecker](/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md), [AdminAccessChecker](/src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md), Initializable
@@ -15,24 +15,31 @@ CampaignData private s_campaignData;
```
-### s_selectedPlatformHash
+### s_platformTreasuryAddress
```solidity
-mapping(bytes32 => bool) private s_selectedPlatformHash;
+mapping(bytes32 => address) private s_platformTreasuryAddress;
```
-### s_platformTreasuryAddress
+### s_platformFeePercent
```solidity
-mapping(bytes32 => address) private s_platformTreasuryAddress;
+mapping(bytes32 => uint256) private s_platformFeePercent;
```
-### s_platformFeePercent
+### s_isSelectedPlatform
```solidity
-mapping(bytes32 => uint256) private s_platformFeePercent;
+mapping(bytes32 => bool) private s_isSelectedPlatform;
+```
+
+
+### s_isApprovedPlatform
+
+```solidity
+mapping(bytes32 => bool) private s_isApprovedPlatform;
```
@@ -43,10 +50,10 @@ mapping(bytes32 => bytes32) private s_platformData;
```
-### s_approvedplatformHash
+### s_approvedPlatformHashes
```solidity
-bytes32[] private s_approvedplatformHash;
+bytes32[] private s_approvedPlatformHashes;
```
@@ -74,7 +81,8 @@ function initialize(
IGlobalParams globalParams,
bytes32[] calldata selectedPlatformHash,
bytes32[] calldata platformDataKey,
- bytes32[] calldata platformDataValue
+ bytes32[] calldata platformDataValue,
+ CampaignData calldata campaignData
) external initializer;
```
@@ -106,6 +114,27 @@ function checkIfPlatformSelected(bytes32 platformHash) public view override retu
|``|`bool`|True if the platform is selected, false otherwise.|
+### checkIfPlatformApproved
+
+*Check if a platform is already approved*
+
+
+```solidity
+function checkIfPlatformApproved(bytes32 platformHash) public view returns (bool);
+```
+**Parameters**
+
+|Name|Type|Description|
+|----|----|-----------|
+|`platformHash`|`bytes32`|The bytes32 identifier of the platform.|
+
+**Returns**
+
+|Name|Type|Description|
+|----|----|-----------|
+|``|`bool`|True if the platform is already approved, false otherwise.|
+
+
### owner
Returns the owner of the contract.
@@ -121,34 +150,34 @@ function owner() public view override(ICampaignInfo, Ownable) returns (address a
|`account`|`address`|The address of the contract owner.|
-### getTotalRaisedAmount
+### getProtocolAdminAddress
-Retrieves the total amount raised in the campaign.
+Retrieves the address of the protocol administrator.
```solidity
-function getTotalRaisedAmount() external view override returns (uint256);
+function getProtocolAdminAddress() public view override returns (address);
```
**Returns**
|Name|Type|Description|
|----|----|-----------|
-|``|`uint256`|The total amount raised in the campaign.|
+|``|`address`|The address of the protocol administrator.|
-### getProtocolAdminAddress
+### getTotalRaisedAmount
-Retrieves the address of the protocol administrator.
+Retrieves the total amount raised in the campaign.
```solidity
-function getProtocolAdminAddress() external view override returns (address);
+function getTotalRaisedAmount() external view override returns (uint256);
```
**Returns**
|Name|Type|Description|
|----|----|-----------|
-|``|`address`|The address of the protocol administrator.|
+|``|`uint256`|The total amount raised in the campaign.|
### getPlatformAdminAddress
@@ -193,7 +222,7 @@ Retrieves the campaign's deadline.
```solidity
-function getDeadline() external view override returns (uint256);
+function getDeadline() public view override returns (uint256);
```
**Returns**
@@ -329,7 +358,12 @@ Can only be called by the current owner.*
```solidity
-function transferOwnership(address newOwner) public override(ICampaignInfo, Ownable) onlyOwner whenNotPaused;
+function transferOwnership(address newOwner)
+ public
+ override(ICampaignInfo, Ownable)
+ onlyOwner
+ whenNotPaused
+ whenNotCancelled;
```
### updateLaunchTime
@@ -338,7 +372,13 @@ Updates the campaign's launch time.
```solidity
-function updateLaunchTime(uint256 launchTime) external override onlyOwner currentTimeIsLess(launchTime) whenNotPaused;
+function updateLaunchTime(uint256 launchTime)
+ external
+ override
+ onlyOwner
+ currentTimeIsLess(getLaunchTime())
+ whenNotPaused
+ whenNotCancelled;
```
**Parameters**
@@ -358,7 +398,8 @@ function updateDeadline(uint256 deadline)
override
onlyOwner
currentTimeIsLess(getLaunchTime())
- whenNotPaused;
+ whenNotPaused
+ whenNotCancelled;
```
**Parameters**
@@ -377,8 +418,9 @@ function updateGoalAmount(uint256 goalAmount)
external
override
onlyOwner
- currentTimeIsLess(s_campaignData.launchTime)
- whenNotPaused;
+ currentTimeIsLess(getLaunchTime())
+ whenNotPaused
+ whenNotCancelled;
```
**Parameters**
@@ -391,14 +433,17 @@ function updateGoalAmount(uint256 goalAmount)
Updates the selection status of a platform for the campaign.
+*It can only be called for a platform if its not approved i.e. the platform treasury is not deployed*
+
```solidity
function updateSelectedPlatform(bytes32 platformHash, bool selection)
external
override
onlyOwner
- currentTimeIsLess(s_campaignData.launchTime)
- whenNotPaused;
+ currentTimeIsLess(getLaunchTime())
+ whenNotPaused
+ whenNotCancelled;
```
**Parameters**
@@ -432,7 +477,7 @@ function _unpauseCampaign(bytes32 message) external onlyProtocolAdmin;
```solidity
-function _cancelCampaign(bytes32 message) external onlyProtocolAdmin;
+function _cancelCampaign(bytes32 message) external;
```
### _setPlatformInfo
@@ -452,21 +497,6 @@ function _setPlatformInfo(bytes32 platformHash, address platformTreasuryAddress)
## Events
-### CampaignInfoPlatformSelected
-*Emitted when a platform is selected for the campaign.*
-
-
-```solidity
-event CampaignInfoPlatformSelected(bytes32 indexed platformHash, address indexed platformTreasury);
-```
-
-**Parameters**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`platformHash`|`bytes32`|The bytes32 identifier of the platform.|
-|`platformTreasury`|`address`|The address of the platform's treasury.|
-
### CampaignInfoLaunchTimeUpdated
*Emitted when the launch time of the campaign is updated.*
@@ -539,21 +569,6 @@ event CampaignInfoPlatformInfoUpdated(bytes32 indexed platformHash, address inde
|`platformHash`|`bytes32`|The bytes32 identifier of the platform.|
|`platformTreasury`|`address`|The address of the platform's treasury.|
-### CampaignInfoOwnershipTransferred
-*Emitted when ownership of the contract is transferred.*
-
-
-```solidity
-event CampaignInfoOwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-```
-
-**Parameters**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`previousOwner`|`address`|The address of the previous owner.|
-|`newOwner`|`address`|The address of the new owner.|
-
## Errors
### CampaignInfoInvalidPlatformUpdate
*Emitted when an invalid platform update is attempted.*
@@ -600,6 +615,20 @@ error CampaignInfoPlatformNotSelected(bytes32 platformHash);
|----|----|-----------|
|`platformHash`|`bytes32`|The bytes32 identifier of the platform.|
+### CampaignInfoPlatformAlreadyApproved
+*Emitted when a platform is already approved for the campaign.*
+
+
+```solidity
+error CampaignInfoPlatformAlreadyApproved(bytes32 platformHash);
+```
+
+**Parameters**
+
+|Name|Type|Description|
+|----|----|-----------|
+|`platformHash`|`bytes32`|The bytes32 identifier of the platform.|
+
## Structs
### Config
@@ -609,9 +638,6 @@ struct Config {
address token;
uint256 protocolFeePercent;
bytes32 identifierHash;
- uint256 launchTime;
- uint256 deadline;
- uint256 goalAmount;
}
```
diff --git a/docs/src/src/CampaignInfoFactory.sol/contract.CampaignInfoFactory.md b/docs/src/src/CampaignInfoFactory.sol/contract.CampaignInfoFactory.md
index e987f012..17439f11 100644
--- a/docs/src/src/CampaignInfoFactory.sol/contract.CampaignInfoFactory.md
+++ b/docs/src/src/CampaignInfoFactory.sol/contract.CampaignInfoFactory.md
@@ -1,8 +1,8 @@
# CampaignInfoFactory
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/CampaignInfoFactory.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/CampaignInfoFactory.sol)
**Inherits:**
-[ICampaignInfoFactory](/src/interfaces/ICampaignInfoFactory.sol/interface.ICampaignInfoFactory.md), Ownable
+Initializable, [ICampaignInfoFactory](/src/interfaces/ICampaignInfoFactory.sol/interface.ICampaignInfoFactory.md), Ownable
Factory contract for creating campaign information contracts.
@@ -71,7 +71,7 @@ constructor(IGlobalParams globalParams, address campaignImplementation) Ownable(
```solidity
-function _initialize(address treasuryFactoryAddress, address globalParams) external onlyOwner;
+function _initialize(address treasuryFactoryAddress, address globalParams) external onlyOwner initializer;
```
**Parameters**
@@ -83,6 +83,8 @@ function _initialize(address treasuryFactoryAddress, address globalParams) exter
### createCampaign
+Creates a new campaign information contract.
+
```solidity
function createCampaign(
@@ -94,6 +96,32 @@ function createCampaign(
CampaignData calldata campaignData
) external override;
```
+**Parameters**
+
+|Name|Type|Description|
+|----|----|-----------|
+|`creator`|`address`|The address of the creator of the campaign.|
+|`identifierHash`|`bytes32`|The unique identifier hash of the campaign.|
+|`selectedPlatformHash`|`bytes32[]`|An array of platform identifiers selected for the campaign.|
+|`platformDataKey`|`bytes32[]`|An array of platform-specific data keys.|
+|`platformDataValue`|`bytes32[]`|An array of platform-specific data values.|
+|`campaignData`|`CampaignData`|The struct containing campaign launch details.|
+
+
+### updateImplementation
+
+Updates the campaign implementation address.
+
+
+```solidity
+function updateImplementation(address newImplementation) external override onlyOwner;
+```
+**Parameters**
+
+|Name|Type|Description|
+|----|----|-----------|
+|`newImplementation`|`address`|The address of the camapaignInfo implementation contract.|
+
## Errors
### CampaignInfoFactoryAlreadyInitialized
@@ -112,12 +140,12 @@ error CampaignInfoFactoryAlreadyInitialized();
error CampaignInfoFactoryInvalidInput();
```
-### CampaignInfoFactoryCampaignCreationFailed
+### CampaignInfoFactoryCampaignInitializationFailed
*Emitted when campaign creation fails.*
```solidity
-error CampaignInfoFactoryCampaignCreationFailed();
+error CampaignInfoFactoryCampaignInitializationFailed();
```
### CampaignInfoFactoryPlatformNotListed
diff --git a/docs/src/src/GlobalParams.sol/contract.GlobalParams.md b/docs/src/src/GlobalParams.sol/contract.GlobalParams.md
index 62896299..c48beca0 100644
--- a/docs/src/src/GlobalParams.sol/contract.GlobalParams.md
+++ b/docs/src/src/GlobalParams.sol/contract.GlobalParams.md
@@ -1,8 +1,8 @@
# GlobalParams
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/GlobalParams.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/GlobalParams.sol)
**Inherits:**
-[IGlobalParams](/src/interfaces/IGlobalParams.sol/interface.IGlobalParams.md), Ownable, Pausable
+[IGlobalParams](/src/interfaces/IGlobalParams.sol/interface.IGlobalParams.md), Ownable
Manages global parameters and platform information.
@@ -127,27 +127,6 @@ constructor(address protocolAdminAddress, address tokenAddress, uint256 protocol
|`protocolFeePercent`|`uint256`|The protocol fee percentage.|
-### checkIfPlatformIsListed
-
-Checks if a platform is listed in the protocol.
-
-
-```solidity
-function checkIfPlatformIsListed(bytes32 platformHash) public view override returns (bool);
-```
-**Parameters**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`platformHash`|`bytes32`||
-
-**Returns**
-
-|Name|Type|Description|
-|----|----|-----------|
-|``|`bool`|True if the platform is listed; otherwise, false.|
-
-
### getPlatformAdminAddress
Retrieves the admin address of a platform.
@@ -266,12 +245,7 @@ Retrieves the owner of platform-specific data.
```solidity
-function getPlatformDataOwner(bytes32 platformDataKey)
- external
- view
- override
- platformIsListed(platformHash)
- returns (bytes32 platformHash);
+function getPlatformDataOwner(bytes32 platformDataKey) external view override returns (bytes32 platformHash);
```
**Parameters**
@@ -286,6 +260,27 @@ function getPlatformDataOwner(bytes32 platformDataKey)
|`platformHash`|`bytes32`|The platform identifier associated with the data.|
+### checkIfPlatformIsListed
+
+Checks if a platform is listed in the protocol.
+
+
+```solidity
+function checkIfPlatformIsListed(bytes32 platformHash) public view override returns (bool);
+```
+**Parameters**
+
+|Name|Type|Description|
+|----|----|-----------|
+|`platformHash`|`bytes32`||
+
+**Returns**
+
+|Name|Type|Description|
+|----|----|-----------|
+|``|`bool`|True if the platform is listed; otherwise, false.|
+
+
### checkIfPlatformDataKeyValid
Checks if a platform-specific data key is valid.
@@ -311,11 +306,14 @@ function checkIfPlatformDataKeyValid(bytes32 platformDataKey) external view over
Enlists a platform with its admin address and fee percentage.
+*The platformFeePercent can be any value including zero.*
+
```solidity
function enlistPlatform(bytes32 platformHash, address platformAdminAddress, uint256 platformFeePercent)
external
- onlyOwner;
+ onlyOwner
+ notAddressZero(platformAdminAddress);
```
**Parameters**
@@ -332,7 +330,7 @@ Delists a platform.
```solidity
-function delistPlatform(bytes32 platformHash) external onlyOwner;
+function delistPlatform(bytes32 platformHash) external onlyOwner platformIsListed(platformHash);
```
**Parameters**
@@ -449,13 +447,13 @@ function updatePlatformAdminAddress(bytes32 platformHash, address platformAdminA
|`platformAdminAddress`|`address`||
-### _checkIfAddressZero
+### _revertIfAddressZero
*Reverts if the input address is zero.*
```solidity
-function _checkIfAddressZero(address account) internal pure;
+function _revertIfAddressZero(address account) internal pure;
```
### _onlyPlatformAdmin
diff --git a/docs/src/src/README.md b/docs/src/src/README.md
index 7423e1d4..7592aab6 100644
--- a/docs/src/src/README.md
+++ b/docs/src/src/README.md
@@ -7,5 +7,4 @@
- [CampaignInfo](CampaignInfo.sol/contract.CampaignInfo.md)
- [CampaignInfoFactory](CampaignInfoFactory.sol/contract.CampaignInfoFactory.md)
- [GlobalParams](GlobalParams.sol/contract.GlobalParams.md)
-- [TestUSD](TestUSD.sol/contract.TestUSD.md)
- [TreasuryFactory](TreasuryFactory.sol/contract.TreasuryFactory.md)
diff --git a/docs/src/src/TestUSD.sol/contract.TestUSD.md b/docs/src/src/TestUSD.sol/contract.TestUSD.md
index 37bc06f1..e317536d 100644
--- a/docs/src/src/TestUSD.sol/contract.TestUSD.md
+++ b/docs/src/src/TestUSD.sol/contract.TestUSD.md
@@ -1,5 +1,5 @@
# TestUSD
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/TestUSD.sol)
+[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/32b7b1617200d0c6f3248845ef972180411f1f65/src/TestUSD.sol)
**Inherits:**
ERC20, Ownable
diff --git a/docs/src/src/TreasuryFactory.sol/contract.TreasuryFactory.md b/docs/src/src/TreasuryFactory.sol/contract.TreasuryFactory.md
index 8cc25e3f..17455ce4 100644
--- a/docs/src/src/TreasuryFactory.sol/contract.TreasuryFactory.md
+++ b/docs/src/src/TreasuryFactory.sol/contract.TreasuryFactory.md
@@ -1,5 +1,5 @@
# TreasuryFactory
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/TreasuryFactory.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/TreasuryFactory.sol)
**Inherits:**
[ITreasuryFactory](/src/interfaces/ITreasuryFactory.sol/interface.ITreasuryFactory.md), [AdminAccessChecker](/src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md)
@@ -9,14 +9,14 @@
### implementationMap
```solidity
-mapping(bytes32 => mapping(uint256 => address)) implementationMap;
+mapping(bytes32 => mapping(uint256 => address)) private implementationMap;
```
### approvedImplementations
```solidity
-mapping(address => bool) approvedImplementations;
+mapping(address => bool) private approvedImplementations;
```
@@ -185,3 +185,9 @@ error TreasuryFactoryImplementationNotSetOrApproved();
error TreasuryFactoryTreasuryInitializationFailed();
```
+### TreasuryFactorySettingPlatformInfoFailed
+
+```solidity
+error TreasuryFactorySettingPlatformInfoFailed();
+```
+
diff --git a/docs/src/src/interfaces/ICampaignData.sol/interface.ICampaignData.md b/docs/src/src/interfaces/ICampaignData.sol/interface.ICampaignData.md
index b2d2439e..c159c65d 100644
--- a/docs/src/src/interfaces/ICampaignData.sol/interface.ICampaignData.md
+++ b/docs/src/src/interfaces/ICampaignData.sol/interface.ICampaignData.md
@@ -1,5 +1,5 @@
# ICampaignData
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/ICampaignData.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/ICampaignData.sol)
An interface for managing campaign data in a CCP.
diff --git a/docs/src/src/interfaces/ICampaignInfo.sol/interface.ICampaignInfo.md b/docs/src/src/interfaces/ICampaignInfo.sol/interface.ICampaignInfo.md
index 8905cd40..09b0d8e5 100644
--- a/docs/src/src/interfaces/ICampaignInfo.sol/interface.ICampaignInfo.md
+++ b/docs/src/src/interfaces/ICampaignInfo.sol/interface.ICampaignInfo.md
@@ -1,5 +1,5 @@
# ICampaignInfo
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/ICampaignInfo.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/ICampaignInfo.sol)
An interface for managing campaign information in a crowdfunding system.
@@ -288,6 +288,8 @@ function updateGoalAmount(uint256 goalAmount) external;
Updates the selection status of a platform for the campaign.
+*It can only be called for a platform if its not approved i.e. the platform treasury is not deployed*
+
```solidity
function updateSelectedPlatform(bytes32 platformHash, bool selection) external;
diff --git a/docs/src/src/interfaces/ICampaignInfoFactory.sol/interface.ICampaignInfoFactory.md b/docs/src/src/interfaces/ICampaignInfoFactory.sol/interface.ICampaignInfoFactory.md
index 59a31f5e..b82c3002 100644
--- a/docs/src/src/interfaces/ICampaignInfoFactory.sol/interface.ICampaignInfoFactory.md
+++ b/docs/src/src/interfaces/ICampaignInfoFactory.sol/interface.ICampaignInfoFactory.md
@@ -1,5 +1,5 @@
# ICampaignInfoFactory
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/ICampaignInfoFactory.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/ICampaignInfoFactory.sol)
**Inherits:**
[ICampaignData](/src/interfaces/ICampaignData.sol/interface.ICampaignData.md)
@@ -35,6 +35,21 @@ function createCampaign(
|`campaignData`|`CampaignData`|The struct containing campaign launch details.|
+### updateImplementation
+
+Updates the campaign implementation address.
+
+
+```solidity
+function updateImplementation(address newImplementation) external;
+```
+**Parameters**
+
+|Name|Type|Description|
+|----|----|-----------|
+|`newImplementation`|`address`|The address of the camapaignInfo implementation contract.|
+
+
## Events
### CampaignInfoFactoryCampaignCreated
Emitted when a campaign is successfully created.
@@ -51,3 +66,11 @@ event CampaignInfoFactoryCampaignCreated(bytes32 indexed identifierHash, address
|`identifierHash`|`bytes32`|The unique identifier hash of the campaign.|
|`campaignInfoAddress`|`address`|The address of the created campaign information contract.|
+### CampaignInfoFactoryCampaignInitialized
+Emitted when the campaign after creation is initialized.
+
+
+```solidity
+event CampaignInfoFactoryCampaignInitialized();
+```
+
diff --git a/docs/src/src/interfaces/ICampaignTreasury.sol/interface.ICampaignTreasury.md b/docs/src/src/interfaces/ICampaignTreasury.sol/interface.ICampaignTreasury.md
index bbfe9c72..bfa758f0 100644
--- a/docs/src/src/interfaces/ICampaignTreasury.sol/interface.ICampaignTreasury.md
+++ b/docs/src/src/interfaces/ICampaignTreasury.sol/interface.ICampaignTreasury.md
@@ -1,5 +1,5 @@
# ICampaignTreasury
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/ICampaignTreasury.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/ICampaignTreasury.sol)
An interface for managing campaign treasury contracts.
@@ -38,13 +38,13 @@ function claimRefund(uint256 tokenId) external;
|`tokenId`|`uint256`|The unique identifier of the refundable token.|
-### getplatformHash
+### getPlatformHash
Retrieves the platform identifier associated with the treasury.
```solidity
-function getplatformHash() external view returns (bytes32);
+function getPlatformHash() external view returns (bytes32);
```
**Returns**
@@ -53,13 +53,13 @@ function getplatformHash() external view returns (bytes32);
|``|`bytes32`|The platform identifier as a bytes32 value.|
-### getplatformFeePercent
+### getPlatformFeePercent
Retrieves the platform fee percentage for the treasury.
```solidity
-function getplatformFeePercent() external view returns (uint256);
+function getPlatformFeePercent() external view returns (uint256);
```
**Returns**
diff --git a/docs/src/src/interfaces/IGlobalParams.sol/interface.IGlobalParams.md b/docs/src/src/interfaces/IGlobalParams.sol/interface.IGlobalParams.md
index 840d1619..447c2b9a 100644
--- a/docs/src/src/interfaces/IGlobalParams.sol/interface.IGlobalParams.md
+++ b/docs/src/src/interfaces/IGlobalParams.sol/interface.IGlobalParams.md
@@ -1,5 +1,5 @@
# IGlobalParams
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/IGlobalParams.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/IGlobalParams.sol)
An interface for accessing and managing global parameters of the protocol.
diff --git a/docs/src/src/interfaces/IItem.sol/interface.IItem.md b/docs/src/src/interfaces/IItem.sol/interface.IItem.md
index e1eef137..1371e884 100644
--- a/docs/src/src/interfaces/IItem.sol/interface.IItem.md
+++ b/docs/src/src/interfaces/IItem.sol/interface.IItem.md
@@ -1,5 +1,5 @@
# IItem
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/IItem.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/IItem.sol)
An interface for managing items and their attributes.
diff --git a/docs/src/src/interfaces/IReward.sol/interface.IReward.md b/docs/src/src/interfaces/IReward.sol/interface.IReward.md
index 46b2cc6d..bd0fdf23 100644
--- a/docs/src/src/interfaces/IReward.sol/interface.IReward.md
+++ b/docs/src/src/interfaces/IReward.sol/interface.IReward.md
@@ -1,5 +1,5 @@
# IReward
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/IReward.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/IReward.sol)
An interface for managing rewards in a campaign.
diff --git a/docs/src/src/interfaces/ITreasuryFactory.sol/interface.ITreasuryFactory.md b/docs/src/src/interfaces/ITreasuryFactory.sol/interface.ITreasuryFactory.md
index 92e54b15..5acfbf2b 100644
--- a/docs/src/src/interfaces/ITreasuryFactory.sol/interface.ITreasuryFactory.md
+++ b/docs/src/src/interfaces/ITreasuryFactory.sol/interface.ITreasuryFactory.md
@@ -1,5 +1,5 @@
# ITreasuryFactory
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/interfaces/ITreasuryFactory.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/interfaces/ITreasuryFactory.sol)
*Interface for the TreasuryFactory contract, which registers, approves, and deploys treasury clones.*
diff --git a/docs/src/src/treasuries/AllOrNothing.sol/contract.AllOrNothing.md b/docs/src/src/treasuries/AllOrNothing.sol/contract.AllOrNothing.md
index ef5a9767..5d719fbc 100644
--- a/docs/src/src/treasuries/AllOrNothing.sol/contract.AllOrNothing.md
+++ b/docs/src/src/treasuries/AllOrNothing.sol/contract.AllOrNothing.md
@@ -1,5 +1,5 @@
# AllOrNothing
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/treasuries/AllOrNothing.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/treasuries/AllOrNothing.sol)
**Inherits:**
[IReward](/src/interfaces/IReward.sol/interface.IReward.md), [BaseTreasury](/src/utils/BaseTreasury.sol/abstract.BaseTreasury.md), [TimestampChecker](/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md), ERC721Burnable
@@ -8,10 +8,17 @@ A contract for handling crowdfunding campaigns with rewards.
## State Variables
-### s_tokenToCollectedAmount
+### s_tokenToTotalCollectedAmount
```solidity
-mapping(uint256 => uint256) private s_tokenToCollectedAmount;
+mapping(uint256 => uint256) private s_tokenToTotalCollectedAmount;
+```
+
+
+### s_tokenToPledgedAmount
+
+```solidity
+mapping(uint256 => uint256) private s_tokenToPledgedAmount;
```
@@ -119,35 +126,18 @@ function getRaisedAmount() external view override returns (uint256);
|``|`uint256`|The total raised amount as a uint256 value.|
-### addReward
-
-Adds a reward to the campaign.
-
-
-```solidity
-function addReward(bytes32 rewardName, Reward calldata reward)
- external
- onlyCampaignOwner
- whenCampaignNotPaused
- whenNotPaused
- whenCampaignNotCancelled
- whenNotCancelled;
-```
-**Parameters**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`rewardName`|`bytes32`|The name of the reward.|
-|`reward`|`Reward`|The details of the reward as a `Reward` struct.|
-
-
-### addRewardsBatch
+### addRewards
Adds multiple rewards in a batch.
+*This function allows for both reward tiers and non-reward tiers.
+For both types, rewards must have non-zero value.
+If items are specified (non-empty arrays), the itemId, itemValue, and itemQuantity arrays must match in length.
+Empty arrays are allowed for both reward tiers and non-reward tiers.*
+
```solidity
-function addRewardsBatch(bytes32[] calldata rewardNames, Reward[] calldata rewards)
+function addRewards(bytes32[] calldata rewardNames, Reward[] calldata rewards)
external
onlyCampaignOwner
whenCampaignNotPaused
@@ -188,6 +178,9 @@ function removeReward(bytes32 rewardName)
Allows a backer to pledge for a reward.
+*The first element of the `reward` array must be a reward tier and the other elements can be either reward tiers or non-reward tiers.
+The non-reward tiers cannot be pledged for without a reward.*
+
```solidity
function pledgeForAReward(address backer, uint256 shippingFee, bytes32[] calldata reward)
@@ -275,20 +268,6 @@ function withdraw() public override whenNotPaused whenNotCancelled;
function cancelTreasury(bytes32 message) public override;
```
-### _pledge
-
-
-```solidity
-function _pledge(
- address backer,
- bytes32 reward,
- uint256 pledgeAmount,
- uint256 shippingFee,
- uint256 tokenId,
- bytes32[] memory rewards
-) internal;
-```
-
### _checkSuccessCondition
*Internal function to check the success condition for fee disbursement.*
@@ -304,6 +283,20 @@ function _checkSuccessCondition() internal view virtual override returns (bool);
|``|`bool`|Whether the success condition is met.|
+### _pledge
+
+
+```solidity
+function _pledge(
+ address backer,
+ bytes32 reward,
+ uint256 pledgeAmount,
+ uint256 shippingFee,
+ uint256 tokenId,
+ bytes32[] memory rewards
+) private;
+```
+
### supportsInterface
@@ -338,20 +331,20 @@ event Receipt(
|`tokenId`|`uint256`|The ID of the token representing the pledge.|
|`rewards`|`bytes32[]`|An array of reward names.|
-### RewardAdded
-*Emitted when a reward is added to the campaign.*
+### RewardsAdded
+*Emitted when rewards are added to the campaign.*
```solidity
-event RewardAdded(bytes32 indexed rewardName, Reward reward);
+event RewardsAdded(bytes32[] rewardNames, Reward[] rewards);
```
**Parameters**
|Name|Type|Description|
|----|----|-----------|
-|`rewardName`|`bytes32`|The name of the reward.|
-|`reward`|`Reward`|The details of the reward.|
+|`rewardNames`|`bytes32[]`|The names of the rewards.|
+|`rewards`|`Reward[]`|The details of the rewards.|
### RewardRemoved
*Emitted when a reward is removed from the campaign.*
diff --git a/docs/src/src/treasuries/MinimumOrder.sol/contract.MinimumOrder.md b/docs/src/src/treasuries/MinimumOrder.sol/contract.MinimumOrder.md
deleted file mode 100644
index 2addf548..00000000
--- a/docs/src/src/treasuries/MinimumOrder.sol/contract.MinimumOrder.md
+++ /dev/null
@@ -1,290 +0,0 @@
-# MinimumOrder
-
-[Git Source](https://github.com/ccprotocol/campaign-utils-contracts-aggregator/blob/79d78188e565502f83e2c0309c9a4ea3b35cee91/src/treasuries/MinimumOrder.sol)
-
-**Inherits:**
-[BaseTreasury](/src/utils/BaseTreasury.sol/abstract.BaseTreasury.md), ERC721Burnable, [TimestampChecker](/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md)
-
-A Solidity contract for managing minimum order-based campaigns.
-Users can pre-order items or rewards, and when a predefined success metric is reached,
-the campaign succeeds, and backers receive their rewards.
-
-## State Variables
-
-### SUCCESS_METRIC
-
-```solidity
-uint256 internal immutable SUCCESS_METRIC;
-```
-
-### s_preOrderValueAmount
-
-```solidity
-uint256 private s_preOrderValueAmount;
-```
-
-### s_platformFeePercent
-
-```solidity
-uint256 private s_platformFeePercent;
-```
-
-### s_tokenToPledgedAmount
-
-```solidity
-mapping(uint256 => uint256) private s_tokenToPledgedAmount;
-```
-
-### s_reward
-
-```solidity
-mapping(bytes32 => Reward) private s_reward;
-```
-
-### s_tokenIdCounter
-
-```solidity
-Counters.Counter private s_tokenIdCounter;
-```
-
-### s_numberOfPreOrders
-
-```solidity
-Counters.Counter internal s_numberOfPreOrders;
-```
-
-## Functions
-
-### constructor
-
-_Constructor for the MinimumOrder contract._
-
-```solidity
-constructor(bytes32 platformHash, address infoAddress) ERC721("", "") BaseTreasury(platformHash, infoAddress);
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| -------------- | --------- | -------------------------------------------------------------------- |
-| `platformHash` | `bytes32` | The unique identifier of the platform. |
-| `infoAddress` | `address` | The address of the CampaignInfo contract providing campaign details. |
-
-### getNumberOfOrders
-
-bytes32 of `PreOrder0MinimumOrder(uint256)`
-
-Function to get the number of pre-orders made.
-
-```solidity
-function getNumberOfOrders() internal view returns (uint256);
-```
-
-**Returns**
-
-| Name | Type | Description |
-| -------- | --------- | ------------------------- |
-| `` | `uint256` | The number of pre-orders. |
-
-### getReward
-
-Function to get reward details by name.
-
-```solidity
-function getReward(bytes32 rewardName) external view returns (Reward memory);
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| ------------ | --------- | ----------------------- |
-| `rewardName` | `bytes32` | The name of the reward. |
-
-**Returns**
-
-| Name | Type | Description |
-| -------- | -------- | ---------------------------------------------------------------------- |
-| `` | `Reward` | The reward details, including value, item IDs, values, and quantities. |
-
-### getRaisedAmount
-
-Function to get the total raised amount during the campaign.
-
-```solidity
-function getRaisedAmount() external view returns (uint256);
-```
-
-**Returns**
-
-| Name | Type | Description |
-| -------- | --------- | ------------------------ |
-| `` | `uint256` | The total raised amount. |
-
-### addReward
-
-Function to add a new reward to the campaign.
-Only the campaign owner can add rewards.
-
-```solidity
-function addReward(bytes32 rewardName, Reward calldata reward)
- external
- onlyCampaignOwner
- whenCampaignNotPaused
- whenNotPaused;
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| ------------ | --------- | ---------------------------------------------------------------------- |
-| `rewardName` | `bytes32` | The name of the reward. |
-| `reward` | `Reward` | The reward details, including value, item IDs, values, and quantities. |
-
-### removeReward
-
-Function to remove a reward from the campaign.
-Only the campaign owner can remove rewards.
-
-```solidity
-function removeReward(bytes32 rewardName) external onlyCampaignOwner whenCampaignNotPaused whenNotPaused;
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| ------------ | --------- | ------------------------------------- |
-| `rewardName` | `bytes32` | The name of the reward to be removed. |
-
-### preOrderForAReward
-
-Function for backers to pre-order a reward.
-The pre-order can only be made within the specified campaign timeframe.
-
-```solidity
-function preOrderForAReward(address backer, bytes32 rewardName)
- public
- virtual
- currentTimeIsWithinRange(INFO.getLaunchTime(), INFO.getDeadline())
- whenCampaignNotPaused
- whenNotPaused;
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| ------------ | --------- | ----------------------------------------------- |
-| `backer` | `address` | The address of the backer making the pre-order. |
-| `rewardName` | `bytes32` | The name of the reward to pre-order. |
-
-### claimRefund
-
-Function for backers to claim a refund if the campaign has not met the success metric.
-
-```solidity
-function claimRefund(uint256 tokenId) external whenCampaignNotPaused whenNotPaused;
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| --------- | --------- | ----------------------------------------------- |
-| `tokenId` | `uint256` | The unique token ID associated with the refund. |
-
-### \_checkSuccessCondition
-
-_Internal function to check the success condition for fee disbursement._
-
-```solidity
-function _checkSuccessCondition() internal view virtual override returns (bool);
-```
-
-**Returns**
-
-| Name | Type | Description |
-| -------- | ------ | ------------------------------------- |
-| `` | `bool` | Whether the success condition is met. |
-
-### supportsInterface
-
-Function to check if an address is supported by the ERC721 contract.
-
-```solidity
-function supportsInterface(bytes4 interfaceId) public view override returns (bool);
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| ------------- | -------- | --------------------------------- |
-| `interfaceId` | `bytes4` | The ERC721 interface ID to check. |
-
-**Returns**
-
-| Name | Type | Description |
-| -------- | ------ | ---------------------------------------------------- |
-| `` | `bool` | True if the interface is supported, false otherwise. |
-
-## Events
-
-### Receipt
-
-_Event emitted when a backer makes a pledge._
-
-```solidity
-event Receipt(address indexed backer, bytes32 indexed reward, uint256 pledgeAmount, uint256 tokenId);
-```
-
-### RewardAdded
-
-_Event emitted when a reward is added to the campaign._
-
-```solidity
-event RewardAdded(bytes32 indexed rewardName, Reward reward);
-```
-
-### RewardRemoved
-
-_Event emitted when a reward is removed from the campaign._
-
-```solidity
-event RewardRemoved(bytes32 indexed rewardName);
-```
-
-### RefundClaimed
-
-_Event emitted when a refund is claimed by a backer._
-
-```solidity
-event RefundClaimed(uint256 tokenId, uint256 refundAmount, address claimer);
-```
-
-## Errors
-
-### PreOrderTransferFailed
-
-_Throws an error indicating that the pre-order transfer failed._
-
-```solidity
-error PreOrderTransferFailed();
-```
-
-### PreOrderInvalidInput
-
-_Throws an error indicating that the pre-order input is invalid._
-
-```solidity
-error PreOrderInvalidInput();
-```
-
-## Structs
-
-### Reward
-
-```solidity
-struct Reward {
- uint256 rewardValue;
- bytes32[] itemId;
- uint256[] itemValue;
- uint256[] itemQuantity;
-}
-```
diff --git a/docs/src/src/treasuries/OutOfStock.sol/contract.OutOfStock.md b/docs/src/src/treasuries/OutOfStock.sol/contract.OutOfStock.md
deleted file mode 100644
index 2c95f9d2..00000000
--- a/docs/src/src/treasuries/OutOfStock.sol/contract.OutOfStock.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# OutOfStock
-
-[Git Source](https://github.com/ccprotocol/campaign-utils-contracts-aggregator/blob/79d78188e565502f83e2c0309c9a4ea3b35cee91/src/treasuries/OutOfStock.sol)
-
-**Inherits:**
-[MinimumOrder](/src/treasuries/MinimumOrder.sol/contract.MinimumOrder.md)
-
-A Solidity contract for managing minimum order-based campaigns with an out-of-stock limit.
-Users can pre-order items or rewards until the out-of-stock limit is reached.
-When the predefined success metric is reached or the out-of-stock limit is reached, the campaign ends.
-
-## Functions
-
-### constructor
-
-_Constructor for the OutOfStock contract._
-
-```solidity
-constructor(bytes32 platformHash, address infoAddress) MinimumOrder(platformHash, infoAddress);
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| -------------- | --------- | -------------------------------------------------------------------- |
-| `platformHash` | `bytes32` | The unique identifier of the platform. |
-| `infoAddress` | `address` | The address of the CampaignInfo contract providing campaign details. |
-
-### preOrderForAReward
-
-Function for backers to pre-order a reward, checking against the out-of-stock limit.
-The pre-order can only be made within the specified campaign timeframe.
-
-```solidity
-function preOrderForAReward(address backer, bytes32 rewardName)
- public
- override
- currentTimeIsWithinRange(INFO.getLaunchTime(), INFO.getDeadline())
- whenCampaignNotPaused
- whenNotPaused;
-```
-
-**Parameters**
-
-| Name | Type | Description |
-| ------------ | --------- | ----------------------------------------------- |
-| `backer` | `address` | The address of the backer making the pre-order. |
-| `rewardName` | `bytes32` | The name of the reward to pre-order. |
-
-## Errors
-
-### OutOfStockLimitReached
-
-_Throws an error indicating the out-of-stock limit has been reached._
-
-```solidity
-error OutOfStockLimitReached();
-```
diff --git a/docs/src/src/utils/AddressCalculator.sol/library.AddressCalculator.md b/docs/src/src/utils/AddressCalculator.sol/library.AddressCalculator.md
deleted file mode 100644
index 6daa3a46..00000000
--- a/docs/src/src/utils/AddressCalculator.sol/library.AddressCalculator.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# AddressCalculator
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/AddressCalculator.sol)
-
-A Solidity library for computing contract addresses and checking if a contract is deployed at a given address.
-
-
-## Functions
-### computeAddress
-
-*Computes the contract address using CREATE2 and checks if the contract is deployed.*
-
-
-```solidity
-function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer)
- internal
- view
- returns (address addr, bool isValid);
-```
-**Parameters**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`salt`|`bytes32`|The salt value used for address computation.|
-|`bytecodeHash`|`bytes32`|The keccak256 hash of the contract's bytecode.|
-|`deployer`|`address`|The address that deploys the contract.|
-
-**Returns**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`addr`|`address`|The computed contract address.|
-|`isValid`|`bool`|True if a contract is deployed at the address; otherwise, false.|
-
-
-### checkIfContractDeployed
-
-*Checks if a contract is deployed at the given address.*
-
-
-```solidity
-function checkIfContractDeployed(address addr) internal view returns (bool isValid);
-```
-**Parameters**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`addr`|`address`|The address to check for contract deployment.|
-
-**Returns**
-
-|Name|Type|Description|
-|----|----|-----------|
-|`isValid`|`bool`|True if a contract is deployed at the address; otherwise, false.|
-
-
diff --git a/docs/src/src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md b/docs/src/src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md
index 6249f4a2..b8065c6a 100644
--- a/docs/src/src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md
+++ b/docs/src/src/utils/AdminAccessChecker.sol/abstract.AdminAccessChecker.md
@@ -1,5 +1,5 @@
# AdminAccessChecker
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/AdminAccessChecker.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/AdminAccessChecker.sol)
*This abstract contract provides access control mechanisms to restrict the execution of specific functions
to authorized protocol administrators and platform administrators.*
diff --git a/docs/src/src/utils/BaseTreasury.sol/abstract.BaseTreasury.md b/docs/src/src/utils/BaseTreasury.sol/abstract.BaseTreasury.md
index 1f9d835e..1b437429 100644
--- a/docs/src/src/utils/BaseTreasury.sol/abstract.BaseTreasury.md
+++ b/docs/src/src/utils/BaseTreasury.sol/abstract.BaseTreasury.md
@@ -1,5 +1,5 @@
# BaseTreasury
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/BaseTreasury.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/BaseTreasury.sol)
**Inherits:**
Initializable, [ICampaignTreasury](/src/interfaces/ICampaignTreasury.sol/interface.ICampaignTreasury.md), [CampaignAccessChecker](/src/utils/CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md), [PausableCancellable](/src/utils/PausableCancellable.sol/abstract.PausableCancellable.md)
@@ -47,13 +47,6 @@ IERC20 internal TOKEN;
```
-### CAMPAIGN_INFO
-
-```solidity
-ICampaignInfo internal CAMPAIGN_INFO;
-```
-
-
### s_pledgedAmount
```solidity
@@ -92,13 +85,13 @@ modifier whenCampaignNotPaused();
modifier whenCampaignNotCancelled();
```
-### getplatformHash
+### getPlatformHash
Retrieves the platform identifier associated with the treasury.
```solidity
-function getplatformHash() external view override returns (bytes32);
+function getPlatformHash() external view override returns (bytes32);
```
**Returns**
@@ -107,13 +100,13 @@ function getplatformHash() external view override returns (bytes32);
|``|`bytes32`|The platform identifier as a bytes32 value.|
-### getplatformFeePercent
+### getPlatformFeePercent
Retrieves the platform fee percentage for the treasury.
```solidity
-function getplatformFeePercent() external view override returns (uint256);
+function getPlatformFeePercent() external view override returns (uint256);
```
**Returns**
diff --git a/docs/src/src/utils/CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md b/docs/src/src/utils/CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md
index 4c39e4e8..153e499e 100644
--- a/docs/src/src/utils/CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md
+++ b/docs/src/src/utils/CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md
@@ -1,5 +1,5 @@
# CampaignAccessChecker
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/CampaignAccessChecker.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/CampaignAccessChecker.sol)
*This abstract contract provides access control mechanisms to restrict the execution of specific functions
to authorized protocol administrators, platform administrators, and campaign owners.*
diff --git a/docs/src/src/utils/Counters.sol/library.Counters.md b/docs/src/src/utils/Counters.sol/library.Counters.md
index d8d77f16..45805f48 100644
--- a/docs/src/src/utils/Counters.sol/library.Counters.md
+++ b/docs/src/src/utils/Counters.sol/library.Counters.md
@@ -1,12 +1,5 @@
# Counters
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/Counters.sol)
-
-**Author:**
-Matt Condon (@shrugs)
-
-*Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
-of elements in a mapping, issuing ERC721 ids, or counting request ids.
-Include with `using Counters for Counters.Counter;`*
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/Counters.sol)
## Functions
@@ -38,6 +31,15 @@ function decrement(Counter storage counter) internal;
function reset(Counter storage counter) internal;
```
+## Errors
+### CounterDecrementOverflow
+*Error thrown when attempting to decrement a counter with value 0.*
+
+
+```solidity
+error CounterDecrementOverflow();
+```
+
## Structs
### Counter
diff --git a/docs/src/src/utils/FiatEnabled.sol/abstract.FiatEnabled.md b/docs/src/src/utils/FiatEnabled.sol/abstract.FiatEnabled.md
index ee22132e..ee5c2c9d 100644
--- a/docs/src/src/utils/FiatEnabled.sol/abstract.FiatEnabled.md
+++ b/docs/src/src/utils/FiatEnabled.sol/abstract.FiatEnabled.md
@@ -1,5 +1,5 @@
# FiatEnabled
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/FiatEnabled.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/FiatEnabled.sol)
A contract that provides functionality for tracking and managing fiat transactions.
This contract allows tracking the amount of fiat raised, individual fiat transactions, and the state of fiat fee disbursement.
diff --git a/docs/src/src/utils/ItemRegistry.sol/contract.ItemRegistry.md b/docs/src/src/utils/ItemRegistry.sol/contract.ItemRegistry.md
index 7ac56706..2e4d08a6 100644
--- a/docs/src/src/utils/ItemRegistry.sol/contract.ItemRegistry.md
+++ b/docs/src/src/utils/ItemRegistry.sol/contract.ItemRegistry.md
@@ -1,5 +1,5 @@
# ItemRegistry
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/ItemRegistry.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/ItemRegistry.sol)
**Inherits:**
[IItem](/src/interfaces/IItem.sol/interface.IItem.md), Context
@@ -87,3 +87,12 @@ event ItemAdded(address indexed owner, bytes32 indexed itemId, Item item);
|`itemId`|`bytes32`|The unique identifier of the item.|
|`item`|`Item`|The item details including actual weight, dimensions, category, and declared currency.|
+## Errors
+### ItemRegistryMismatchedArraysLength
+*Thrown when the input arrays have mismatched lengths.*
+
+
+```solidity
+error ItemRegistryMismatchedArraysLength();
+```
+
diff --git a/docs/src/src/utils/PausableCancellable.sol/abstract.PausableCancellable.md b/docs/src/src/utils/PausableCancellable.sol/abstract.PausableCancellable.md
index d13dcff3..cd083e89 100644
--- a/docs/src/src/utils/PausableCancellable.sol/abstract.PausableCancellable.md
+++ b/docs/src/src/utils/PausableCancellable.sol/abstract.PausableCancellable.md
@@ -1,5 +1,5 @@
# PausableCancellable
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/PausableCancellable.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/PausableCancellable.sol)
Abstract contract providing pause and cancel state management with events and modifiers
diff --git a/docs/src/src/utils/PausableWithMsg.sol/abstract.PausableWithMsg.md b/docs/src/src/utils/PausableWithMsg.sol/abstract.PausableWithMsg.md
deleted file mode 100644
index b5ad4586..00000000
--- a/docs/src/src/utils/PausableWithMsg.sol/abstract.PausableWithMsg.md
+++ /dev/null
@@ -1,110 +0,0 @@
-# PausableWithMsg
-[Git Source](https://github.com/ccprotocol/campaign-utils-contracts-aggregator/blob/79d78188e565502f83e2c0309c9a4ea3b35cee91/src/utils/PausableWithMsg.sol)
-
-
-## State Variables
-### _paused
-
-```solidity
-bool private _paused;
-```
-
-
-## Functions
-### constructor
-
-*Initializes the contract in unpaused state.*
-
-
-```solidity
-constructor();
-```
-
-### whenNotPaused
-
-*Modifier to make a function callable only when the contract is not paused.
-Requirements:
-- The contract must not be paused.*
-
-
-```solidity
-modifier whenNotPaused();
-```
-
-### whenPaused
-
-*Modifier to make a function callable only when the contract is paused.
-Requirements:
-- The contract must be paused.*
-
-
-```solidity
-modifier whenPaused();
-```
-
-### paused
-
-*Returns true if the contract is paused, and false otherwise.*
-
-
-```solidity
-function paused() public view virtual returns (bool);
-```
-
-### _requireNotPaused
-
-*Throws if the contract is paused.*
-
-
-```solidity
-function _requireNotPaused() internal view virtual;
-```
-
-### _requirePaused
-
-*Throws if the contract is not paused.*
-
-
-```solidity
-function _requirePaused() internal view virtual;
-```
-
-### _pause
-
-*Triggers stopped state.
-Requirements:
-- The contract must not be paused.*
-
-
-```solidity
-function _pause(bytes32 message) internal virtual whenNotPaused;
-```
-
-### _unpause
-
-*Returns to normal state.
-Requirements:
-- The contract must be paused.*
-
-
-```solidity
-function _unpause(bytes32 message) internal virtual whenPaused;
-```
-
-## Events
-### Paused
-*Emitted when the pause is triggered by `account`.*
-
-
-```solidity
-event Paused(address account, bytes32 message);
-```
-
-### Unpaused
-*Emitted when the pause is lifted by `account`.*
-
-
-```solidity
-event Unpaused(address account, bytes32 message);
-```
-
diff --git a/docs/src/src/utils/README.md b/docs/src/src/utils/README.md
index a8b376bf..41bc0ddb 100644
--- a/docs/src/src/utils/README.md
+++ b/docs/src/src/utils/README.md
@@ -1,7 +1,6 @@
# Contents
-- [AddressCalculator](AddressCalculator.sol/library.AddressCalculator.md)
- [AdminAccessChecker](AdminAccessChecker.sol/abstract.AdminAccessChecker.md)
- [BaseTreasury](BaseTreasury.sol/abstract.BaseTreasury.md)
- [CampaignAccessChecker](CampaignAccessChecker.sol/abstract.CampaignAccessChecker.md)
diff --git a/docs/src/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md b/docs/src/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md
index d75b4cdd..ae8c27a2 100644
--- a/docs/src/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md
+++ b/docs/src/src/utils/TimestampChecker.sol/abstract.TimestampChecker.md
@@ -1,5 +1,5 @@
# TimestampChecker
-[Git Source](https://github.com/ccprotocol/reference-client-sc/blob/13d9d746c7f79b76f03c178fe64b679ba803191a/src/utils/TimestampChecker.sol)
+[Git Source](https://github.com/ccprotocol/ccprotocol-contracts/blob/b6945e2b533f7d9aacb156ae915f6d1bb6b199de/src/utils/TimestampChecker.sol)
A contract that provides timestamp-related checks for contract functions.
@@ -51,13 +51,13 @@ modifier currentTimeIsWithinRange(uint256 initialTime, uint256 finalTime);
|`finalTime`|`uint256`|The final timestamp of the range.|
-### _checkIfCurrentTimeIsLess
+### _revertIfCurrentTimeIsNotLess
-*Internal function to check if the current timestamp is less than or equal a specified time.*
+*Internal function to revert if the current timestamp is less than or equal a specified time.*
```solidity
-function _checkIfCurrentTimeIsLess(uint256 inputTime) internal view virtual;
+function _revertIfCurrentTimeIsNotLess(uint256 inputTime) internal view virtual;
```
**Parameters**
@@ -66,13 +66,13 @@ function _checkIfCurrentTimeIsLess(uint256 inputTime) internal view virtual;
|`inputTime`|`uint256`|The timestamp being checked against.|
-### _checkIfCurrentTimeIsGreater
+### _revertIfCurrentTimeIsNotGreater
-*Internal function to check if the current timestamp is greater than or equal a specified time.*
+*Internal function to revert if the current timestamp is not greater than or equal a specified time.*
```solidity
-function _checkIfCurrentTimeIsGreater(uint256 inputTime) internal view virtual;
+function _revertIfCurrentTimeIsNotGreater(uint256 inputTime) internal view virtual;
```
**Parameters**
@@ -81,13 +81,13 @@ function _checkIfCurrentTimeIsGreater(uint256 inputTime) internal view virtual;
|`inputTime`|`uint256`|The timestamp being checked against.|
-### _checkIfCurrentTimeIsWithinRange
+### _revertIfCurrentTimeIsNotWithinRange
-*Internal function to check if the current timestamp is within a specified time range.*
+*Internal function to revert if the current timestamp is not within a specified time range.*
```solidity
-function _checkIfCurrentTimeIsWithinRange(uint256 initialTime, uint256 finalTime) internal view virtual;
+function _revertIfCurrentTimeIsNotWithinRange(uint256 initialTime, uint256 finalTime) internal view virtual;
```
**Parameters**
diff --git a/env.example b/env.example
index 4c5b7440..9265a035 100644
--- a/env.example
+++ b/env.example
@@ -1,17 +1,71 @@
-# -------------------------
-# Deploy Config
-# -------------------------
+# =========================
+# Deploy Configuration
+# =========================
+
+# Wallet and RPC
PRIVATE_KEY=
RPC_URL=
-# Optionally set this to reuse already-deployed contracts.
-# If any are left blank, they will be freshly deployed.
+# Optional: Separate RPC URLs for multiple chains
+ALFAJORES_RPC_URL=
+CELO_RPC_URL=
+
+# Chain IDs
+CHAIN_ID=
+ALFAJORES_CHAIN_ID=
+CELO_CHAIN_ID=
+
-# -------------------------
+# =========================
# Contract Addresses
-# -------------------------
-TEST_USD_ADDRESS=""
-GLOBAL_PARAMS_ADDRESS=""
-TREASURY_FACTORY_ADDRESS=""
-CAMPAIGN_INFO_FACTORY_ADDRESS=""
-SIMULATE=true
\ No newline at end of file
+# =========================
+
+# Optional: Reuse already-deployed contracts
+TOKEN_ADDRESS=
+GLOBAL_PARAMS_ADDRESS=
+TREASURY_FACTORY_ADDRESS=
+CAMPAIGN_INFO_FACTORY_ADDRESS=
+
+
+# =========================
+# Protocol Parameters
+# =========================
+
+PROTOCOL_ADMIN_ADDRESS=
+PROTOCOL_FEE_PERCENT=
+
+
+# =========================
+# Platform Parameters
+# =========================
+
+PLATFORM_NAME=
+PLATFORM_ADMIN_ADDRESS=
+PLATFORM_FEE_PERCENT=
+
+
+# =========================
+# Token Setup
+# =========================
+
+# Only required if TOKEN needs to be pre-minted
+TOKEN_MINT_AMOUNT=
+TOKEN_NAME=""
+TOKEN_SYMBOL=""
+BACKER1_ADDRESS=
+BACKER2_ADDRESS=
+
+
+# =========================
+# Simulation
+# =========================
+
+# Set to "true" or "false" only
+SIMULATE=
+
+
+# =========================
+# Verification
+# =========================
+
+ETHERSCAN_API_KEY=
diff --git a/foundry.toml b/foundry.toml
index 3c29c44e..95ee243f 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -11,6 +11,6 @@ remappings = [
"@openzeppelin/=lib/openzeppelin-contracts/"
]
-
[rpc_endpoints]
-alfajores = "${ALFAJORES_RPC_URL}"
+mainnet = "https://forno.celo.org/"
+alfajores = "https://alfajores-forno.celo-testnet.org/"
diff --git a/script/DeployAll.s.sol b/script/DeployAll.s.sol
index 741a3208..f7936213 100644
--- a/script/DeployAll.s.sol
+++ b/script/DeployAll.s.sol
@@ -1,21 +1,22 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "forge-std/Script.sol";
-import "./DeployGlobalParams.s.sol";
-import "./DeployTestUSD.s.sol";
-import "./DeployCampaignInfoFactory.s.sol";
-import "./DeployTreasuryFactory.s.sol";
+import {Script} from "forge-std/Script.sol";
+import {console2} from "forge-std/console2.sol";
+import {DeployGlobalParams} from "./DeployGlobalParams.s.sol";
+import {DeployTestToken} from "./DeployTestToken.s.sol";
+import {DeployCampaignInfoFactory} from "./DeployCampaignInfoFactory.s.sol";
+import {DeployTreasuryFactory} from "./DeployTreasuryFactory.s.sol";
contract DeployAll is Script {
- function deployTestUSD() internal returns (address) {
- DeployTestUSD script = new DeployTestUSD();
+ function deployTestToken() internal returns (address) {
+ DeployTestToken script = new DeployTestToken();
return script.deploy();
}
- function deployGlobalParams(address testUSD) internal returns (address) {
+ function deployGlobalParams(address testToken) internal returns (address) {
DeployGlobalParams script = new DeployGlobalParams();
- return script.deployWithToken(testUSD);
+ return script.deployWithToken(testToken);
}
function deployTreasuryFactory(
@@ -41,8 +42,8 @@ contract DeployAll is Script {
vm.startBroadcast(deployerKey);
}
- address testUSD = deployTestUSD();
- address globalParams = deployGlobalParams(testUSD);
+ address testToken = deployTestToken();
+ address globalParams = deployGlobalParams(testToken);
address treasuryFactory = deployTreasuryFactory(globalParams);
address campaignFactory = deployCampaignFactory(
globalParams,
@@ -53,7 +54,7 @@ contract DeployAll is Script {
vm.stopBroadcast();
}
- console2.log("TEST_USD_ADDRESS", testUSD);
+ console2.log("TOKEN_ADDRESS", testToken);
console2.log("GLOBAL_PARAMS_ADDRESS", globalParams);
console2.log("TREASURY_FACTORY_ADDRESS", treasuryFactory);
console2.log("CAMPAIGN_INFO_FACTORY_ADDRESS", campaignFactory);
diff --git a/script/DeployAllAndSetupAllOrNothing.s.sol b/script/DeployAllAndSetupAllOrNothing.s.sol
new file mode 100644
index 00000000..d0dc456c
--- /dev/null
+++ b/script/DeployAllAndSetupAllOrNothing.s.sol
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import {Script} from "forge-std/Script.sol";
+import {console2} from "forge-std/console2.sol";
+import {TestToken} from "../test/mocks/TestToken.sol";
+import {GlobalParams} from "src/GlobalParams.sol";
+import {CampaignInfoFactory} from "src/CampaignInfoFactory.sol";
+import {CampaignInfo} from "src/CampaignInfo.sol";
+import {TreasuryFactory} from "src/TreasuryFactory.sol";
+import {AllOrNothing} from "src/treasuries/AllOrNothing.sol";
+
+/**
+ * @notice Script to deploy and setup all needed contracts for the protocol
+ */
+contract DeployAllAndSetupAllOrNothing is Script {
+ // Customizable values (set through environment variables)
+ bytes32 platformHash;
+ uint256 protocolFeePercent;
+ uint256 platformFeePercent;
+ uint256 tokenMintAmount;
+ bool simulate;
+
+ // Contract addresses
+ address testToken;
+ address globalParams;
+ address campaignInfoImplementation;
+ address treasuryFactory;
+ address campaignInfoFactory;
+ address allOrNothingImplementation;
+
+ // User addresses
+ address deployerAddress;
+ address finalProtocolAdmin;
+ address finalPlatformAdmin;
+ address backer1;
+ address backer2;
+
+ // Token details
+ // string tokenName;
+ // string tokenSymbol;
+
+ // Flags to track what was completed
+ bool platformEnlisted = false;
+ bool implementationRegistered = false;
+ bool implementationApproved = false;
+ bool adminRightsTransferred = false;
+
+ // Flags for contract deployment or reuse
+ bool testTokenDeployed = false;
+ bool globalParamsDeployed = false;
+ bool treasuryFactoryDeployed = false;
+ bool campaignInfoFactoryDeployed = false;
+ bool allOrNothingDeployed = false;
+
+ // Configure parameters based on environment variables
+ function setupParams() internal {
+ // Get customizable values
+ string memory platformName = vm.envOr(
+ "PLATFORM_NAME",
+ string("MiniFunder")
+ );
+
+ platformHash = keccak256(abi.encodePacked(platformName));
+ protocolFeePercent = vm.envOr("PROTOCOL_FEE_PERCENT", uint256(100)); // Default 1%
+ platformFeePercent = vm.envOr("PLATFORM_FEE_PERCENT", uint256(400)); // Default 4%
+ tokenMintAmount = vm.envOr("TOKEN_MINT_AMOUNT", uint256(10000000e18));
+ simulate = vm.envOr("SIMULATE", false);
+
+ // Get user addresses
+ uint256 deployerKey = vm.envUint("PRIVATE_KEY");
+ deployerAddress = vm.addr(deployerKey);
+
+ // These are the final admin addresses that will receive control
+ finalProtocolAdmin = vm.envOr(
+ "PROTOCOL_ADMIN_ADDRESS",
+ deployerAddress
+ );
+ finalPlatformAdmin = vm.envOr(
+ "PLATFORM_ADMIN_ADDRESS",
+ deployerAddress
+ );
+ backer1 = vm.envOr("BACKER1_ADDRESS", address(0));
+ backer2 = vm.envOr("BACKER2_ADDRESS", address(0));
+
+ // Check for existing contract addresses
+ testToken = vm.envOr("TOKEN_ADDRESS", address(0));
+ globalParams = vm.envOr("GLOBAL_PARAMS_ADDRESS", address(0));
+ treasuryFactory = vm.envOr("TREASURY_FACTORY_ADDRESS", address(0));
+ campaignInfoFactory = vm.envOr(
+ "CAMPAIGN_INFO_FACTORY_ADDRESS",
+ address(0)
+ );
+ allOrNothingImplementation = vm.envOr(
+ "ALL_OR_NOTHING_IMPLEMENTATION_ADDRESS",
+ address(0)
+ );
+
+ console2.log("Using platform hash for:", platformName);
+ console2.log("Protocol fee percent:", protocolFeePercent);
+ console2.log("Platform fee percent:", platformFeePercent);
+ console2.log("Simulation mode:", simulate);
+ console2.log("Deployer address:", deployerAddress);
+ console2.log("Final protocol admin:", finalProtocolAdmin);
+ console2.log("Final platform admin:", finalPlatformAdmin);
+ }
+
+ // Deploy or reuse contracts
+ function deployContracts() internal {
+ console2.log("Setting up contracts...");
+
+ // Deploy or reuse TestToken
+
+ string memory tokenName = vm.envOr("TOKEN_NAME", string("TestToken"));
+ string memory tokenSymbol = vm.envOr("TOKEN_SYMBOL", string("TST"));
+
+ if (testToken == address(0)) {
+ testToken = address(new TestToken(tokenName, tokenSymbol));
+ testTokenDeployed = true;
+ console2.log("TestToken deployed at:", testToken);
+ } else {
+ console2.log("Reusing TestToken at:", testToken);
+ }
+
+ // Deploy or reuse GlobalParams
+ if (globalParams == address(0)) {
+ globalParams = address(
+ new GlobalParams(
+ deployerAddress, // Initially deployer is protocol admin
+ testToken,
+ protocolFeePercent
+ )
+ );
+ globalParamsDeployed = true;
+ console2.log("GlobalParams deployed at:", globalParams);
+ } else {
+ console2.log("Reusing GlobalParams at:", globalParams);
+ }
+
+ // We need at least TestToken and GlobalParams to continue
+ require(testToken != address(0), "TestToken address is required");
+ require(globalParams != address(0), "GlobalParams address is required");
+
+ // Deploy CampaignInfo implementation if needed for new deployments
+ if (campaignInfoFactory == address(0)) {
+ campaignInfoImplementation = address(
+ new CampaignInfo(address(this))
+ );
+ console2.log(
+ "CampaignInfo implementation deployed at:",
+ campaignInfoImplementation
+ );
+ }
+
+ // Deploy or reuse TreasuryFactory
+ if (treasuryFactory == address(0)) {
+ treasuryFactory = address(
+ new TreasuryFactory(GlobalParams(globalParams))
+ );
+ treasuryFactoryDeployed = true;
+ console2.log("TreasuryFactory deployed at:", treasuryFactory);
+ } else {
+ console2.log("Reusing TreasuryFactory at:", treasuryFactory);
+ }
+
+ // Deploy or reuse CampaignInfoFactory
+ if (campaignInfoFactory == address(0)) {
+ campaignInfoFactory = address(
+ new CampaignInfoFactory(
+ GlobalParams(globalParams),
+ campaignInfoImplementation
+ )
+ );
+ CampaignInfoFactory(campaignInfoFactory)._initialize(
+ treasuryFactory,
+ globalParams
+ );
+ campaignInfoFactoryDeployed = true;
+ console2.log(
+ "CampaignInfoFactory deployed and initialized at:",
+ campaignInfoFactory
+ );
+ } else {
+ console2.log(
+ "Reusing CampaignInfoFactory at:",
+ campaignInfoFactory
+ );
+ }
+
+ // Deploy or reuse AllOrNothing implementation
+ if (allOrNothingImplementation == address(0)) {
+ allOrNothingImplementation = address(new AllOrNothing());
+ allOrNothingDeployed = true;
+ console2.log(
+ "AllOrNothing implementation deployed at:",
+ allOrNothingImplementation
+ );
+ } else {
+ console2.log(
+ "Reusing AllOrNothing implementation at:",
+ allOrNothingImplementation
+ );
+ }
+ }
+
+ // Setup steps when deployer has all roles
+ function enlistPlatform() internal {
+ // Skip if we didn't deploy GlobalParams (assuming it's already set up)
+ if (!globalParamsDeployed) {
+ console2.log(
+ "Skipping enlistPlatform - using existing GlobalParams"
+ );
+ platformEnlisted = true;
+ return;
+ }
+
+ console2.log("Setting up: enlistPlatform");
+ // Only use startPrank in simulation mode
+ if (simulate) {
+ vm.startPrank(deployerAddress);
+ }
+
+ GlobalParams(globalParams).enlistPlatform(
+ platformHash,
+ deployerAddress, // Initially deployer is platform admin
+ platformFeePercent
+ );
+
+ if (simulate) {
+ vm.stopPrank();
+ }
+ platformEnlisted = true;
+ console2.log("Platform enlisted successfully");
+ }
+
+ function registerTreasuryImplementation() internal {
+ // Skip if we didn't deploy TreasuryFactory (assuming it's already set up)
+ if (!treasuryFactoryDeployed || !allOrNothingDeployed) {
+ console2.log(
+ "Skipping registerTreasuryImplementation - using existing contracts"
+ );
+ implementationRegistered = true;
+ return;
+ }
+
+ console2.log("Setting up: registerTreasuryImplementation");
+ // Only use startPrank in simulation mode
+ if (simulate) {
+ vm.startPrank(deployerAddress);
+ }
+
+ TreasuryFactory(treasuryFactory).registerTreasuryImplementation(
+ platformHash,
+ 0, // Implementation ID
+ allOrNothingImplementation
+ );
+
+ if (simulate) {
+ vm.stopPrank();
+ }
+ implementationRegistered = true;
+ console2.log("Treasury implementation registered successfully");
+ }
+
+ function approveTreasuryImplementation() internal {
+ // Skip if we didn't deploy TreasuryFactory (assuming it's already set up)
+ if (!treasuryFactoryDeployed || !allOrNothingDeployed) {
+ console2.log(
+ "Skipping approveTreasuryImplementation - using existing contracts"
+ );
+ implementationApproved = true;
+ return;
+ }
+
+ console2.log("Setting up: approveTreasuryImplementation");
+ // Only use startPrank in simulation mode
+ if (simulate) {
+ vm.startPrank(deployerAddress);
+ }
+
+ TreasuryFactory(treasuryFactory).approveTreasuryImplementation(
+ platformHash,
+ 0 // Implementation ID
+ );
+
+ if (simulate) {
+ vm.stopPrank();
+ }
+ implementationApproved = true;
+ console2.log("Treasury implementation approved successfully");
+ }
+
+ function mintTokens() internal {
+ // Only mint tokens if we deployed TestToken
+ if (!testTokenDeployed) {
+ console2.log("Skipping mintTokens - using existing TestToken");
+ return;
+ }
+
+ if (backer1 != address(0) && backer2 != address(0)) {
+ console2.log("Minting tokens to test backers");
+ TestToken(testToken).mint(backer1, tokenMintAmount);
+ if (backer1 != backer2) {
+ TestToken(testToken).mint(backer2, tokenMintAmount);
+ }
+ console2.log("Tokens minted successfully");
+ }
+ }
+
+ // Transfer admin rights to final addresses
+ function transferAdminRights() internal {
+ // Skip if we didn't deploy GlobalParams (assuming it's already set up)
+ if (!globalParamsDeployed) {
+ console2.log(
+ "Skipping transferAdminRights - using existing GlobalParams"
+ );
+ adminRightsTransferred = true;
+ return;
+ }
+
+ console2.log("Transferring admin rights to final addresses...");
+
+ // Only transfer if the final addresses are different from deployer
+ if (finalProtocolAdmin != deployerAddress) {
+ console2.log(
+ "Transferring protocol admin rights to:",
+ finalProtocolAdmin
+ );
+ GlobalParams(globalParams).updateProtocolAdminAddress(
+ finalProtocolAdmin
+ );
+ }
+
+ if (finalPlatformAdmin != deployerAddress) {
+ console2.log(
+ "Updating platform admin address for platform hash:",
+ vm.toString(platformHash)
+ );
+ GlobalParams(globalParams).updatePlatformAdminAddress(
+ platformHash,
+ finalPlatformAdmin
+ );
+ }
+
+ adminRightsTransferred = true;
+ console2.log("Admin rights transferred successfully");
+ }
+
+ function run() external {
+ // Load configuration
+ setupParams();
+
+ uint256 deployerKey = vm.envUint("PRIVATE_KEY");
+
+ // Start broadcast with deployer key
+ vm.startBroadcast(deployerKey);
+
+ // Deploy or reuse contracts
+ deployContracts();
+
+ // Setup the protocol with individual transactions in the correct order
+ // Since deployer is both protocol and platform admin initially, we can do all steps
+ enlistPlatform();
+ registerTreasuryImplementation();
+ approveTreasuryImplementation();
+
+ // Mint tokens if needed
+ mintTokens();
+
+ // Finally, transfer admin rights to the final addresses
+ transferAdminRights();
+
+ // Stop broadcast
+ vm.stopBroadcast();
+
+ // Output summary
+ console2.log("\n--- Deployment & Setup Summary ---");
+ console2.log("Platform Name Hash:", vm.toString(platformHash));
+ console2.log("TOKEN_ADDRESS:", testToken);
+ console2.log("GLOBAL_PARAMS_ADDRESS:", globalParams);
+ if (campaignInfoImplementation != address(0)) {
+ console2.log(
+ "CAMPAIGN_INFO_IMPLEMENTATION_ADDRESS:",
+ campaignInfoImplementation
+ );
+ }
+ console2.log("TREASURY_FACTORY_ADDRESS:", treasuryFactory);
+ console2.log("CAMPAIGN_INFO_FACTORY_ADDRESS:", campaignInfoFactory);
+ console2.log(
+ "ALL_OR_NOTHING_IMPLEMENTATION_ADDRESS:",
+ allOrNothingImplementation
+ );
+ console2.log("Protocol Admin:", finalProtocolAdmin);
+ console2.log("Platform Admin:", finalPlatformAdmin);
+
+ if (backer1 != address(0)) {
+ console2.log("Backer1 (tokens minted):", backer1);
+ }
+ if (backer2 != address(0) && backer1 != backer2) {
+ console2.log("Backer2 (tokens minted):", backer2);
+ }
+
+ console2.log("\nDeployment status:");
+ console2.log(
+ "- TestToken:",
+ testTokenDeployed ? "Newly deployed" : "Reused existing"
+ );
+ console2.log(
+ "- GlobalParams:",
+ globalParamsDeployed ? "Newly deployed" : "Reused existing"
+ );
+ console2.log(
+ "- TreasuryFactory:",
+ treasuryFactoryDeployed ? "Newly deployed" : "Reused existing"
+ );
+ console2.log(
+ "- CampaignInfoFactory:",
+ campaignInfoFactoryDeployed ? "Newly deployed" : "Reused existing"
+ );
+ console2.log(
+ "- AllOrNothing Implementation:",
+ allOrNothingDeployed ? "Newly deployed" : "Reused existing"
+ );
+
+ console2.log("\nSetup steps:");
+ console2.log("1. Platform enlisted:", platformEnlisted);
+ console2.log(
+ "2. Treasury implementation registered:",
+ implementationRegistered
+ );
+ console2.log(
+ "3. Treasury implementation approved:",
+ implementationApproved
+ );
+ console2.log("4. Admin rights transferred:", adminRightsTransferred);
+
+ console2.log("\nDeployment and setup completed successfully!");
+ }
+}
diff --git a/script/DeployAllOrNothingImplementation.s.sol b/script/DeployAllOrNothingImplementation.s.sol
new file mode 100644
index 00000000..7c017a50
--- /dev/null
+++ b/script/DeployAllOrNothingImplementation.s.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import {Script} from "forge-std/Script.sol";
+import {console2} from "forge-std/console2.sol";
+import {AllOrNothing} from "src/treasuries/AllOrNothing.sol";
+
+contract DeployAllOrNothingImplementation is Script {
+ function deploy() public returns (address) {
+ console2.log("Deploying AllOrNothingImplementation...");
+ AllOrNothing allOrNothingImplementation = new AllOrNothing();
+ console2.log(
+ "AllOrNothingImplementation deployed at:",
+ address(allOrNothingImplementation)
+ );
+ return address(allOrNothingImplementation);
+ }
+
+ function run() external {
+ uint256 deployerKey = vm.envUint("PRIVATE_KEY");
+ bool simulate = vm.envOr("SIMULATE", false);
+
+ if (!simulate) {
+ vm.startBroadcast(deployerKey);
+ }
+
+ address implementationAddress = deploy();
+
+ if (!simulate) {
+ vm.stopBroadcast();
+ }
+
+ console2.log(
+ "ALL_OR_NOTHING_IMPLEMENTATION_ADDRESS",
+ implementationAddress
+ );
+ }
+}
diff --git a/script/DeployCampaignInfoFactory.s.sol b/script/DeployCampaignInfoFactory.s.sol
index 6fc116d0..cbf00748 100644
--- a/script/DeployCampaignInfoFactory.s.sol
+++ b/script/DeployCampaignInfoFactory.s.sol
@@ -1,47 +1,57 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import {CampaignInfo} from "../src/CampaignInfo.sol";
-import {CampaignInfoFactory} from "../src/CampaignInfoFactory.sol";
-import {GlobalParams} from "../src/GlobalParams.sol";
-import {TreasuryFactory} from "../src/TreasuryFactory.sol";
+import {Script} from "forge-std/Script.sol";
+import {console2} from "forge-std/console2.sol";
+import {CampaignInfoFactory} from "src/CampaignInfoFactory.sol";
+import {CampaignInfo} from "src/CampaignInfo.sol";
+import {GlobalParams} from "src/GlobalParams.sol";
import {DeployBase} from "./lib/DeployBase.s.sol";
contract DeployCampaignInfoFactory is DeployBase {
function deploy(
- address _globalParams,
- address _treasuryFactory
+ address globalParams,
+ address treasuryFactory
) public returns (address) {
- require(_globalParams != address(0), "GlobalParams not set");
- require(_treasuryFactory != address(0), "TreasuryFactory not set");
+ console2.log("Deploying CampaignInfoFactory...");
- // Deploy CampaignInfo implementation
- CampaignInfo campaignInfo = new CampaignInfo(msg.sender);
+ // Properly deploy CampaignInfo with direct instantiation
+ CampaignInfo campaignInfoImpl = new CampaignInfo(address(this));
+ address campaignInfo = address(campaignInfoImpl);
+ console2.log("CampaignInfo implementation deployed at:", campaignInfo);
- // Deploy CampaignInfoFactory
- CampaignInfoFactory factory = new CampaignInfoFactory(
- GlobalParams(_globalParams),
- address(campaignInfo)
+ // Create and initialize the factory
+ CampaignInfoFactory campaignInfoFactory = new CampaignInfoFactory(
+ GlobalParams(globalParams),
+ campaignInfo
);
- // Initialize the factory
- factory._initialize(_treasuryFactory, _globalParams);
+ campaignInfoFactory._initialize(treasuryFactory, globalParams);
- return address(factory);
+ console2.log(
+ "CampaignInfoFactory deployed and initialized at:",
+ address(campaignInfoFactory)
+ );
+ return address(campaignInfoFactory);
}
function run() external {
- address globalParams = vm.envOr("GLOBAL_PARAMS_ADDRESS", address(0));
- address treasuryFactory = vm.envOr(
- "TREASURY_FACTORY_ADDRESS",
- address(0)
- );
+ uint256 deployerKey = vm.envUint("PRIVATE_KEY");
+ bool simulate = vm.envOr("SIMULATE", false);
+
+ address globalParams = vm.envAddress("GLOBAL_PARAMS_ADDRESS");
+ address treasuryFactory = vm.envAddress("TREASURY_FACTORY_ADDRESS");
+
+ if (!simulate) {
+ vm.startBroadcast(deployerKey);
+ }
+
+ address factoryAddress = deploy(globalParams, treasuryFactory);
- require(globalParams != address(0), "GlobalParams must be set");
- require(treasuryFactory != address(0), "TreasuryFactory must be set");
+ if (!simulate) {
+ vm.stopBroadcast();
+ }
- vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
- deploy(globalParams, treasuryFactory);
- vm.stopBroadcast();
+ console2.log("CAMPAIGN_INFO_FACTORY_ADDRESS", factoryAddress);
}
-}
\ No newline at end of file
+}
diff --git a/script/DeployCampaignInfoImplementation.s.sol b/script/DeployCampaignInfoImplementation.s.sol
new file mode 100644
index 00000000..dd4f4dc6
--- /dev/null
+++ b/script/DeployCampaignInfoImplementation.s.sol
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import {Script} from "forge-std/Script.sol";
+import {console2} from "forge-std/console2.sol";
+import {CampaignInfo} from "src/CampaignInfo.sol";
+
+contract DeployCampaignInfoImplementation is Script {
+ function deploy() public returns (address) {
+ console2.log("Deploying CampaignInfo implementation...");
+ // Implementation will use the script address as admin, but this will be replaced
+ // when the factory creates new instances
+ CampaignInfo campaignInfo = new CampaignInfo(address(this));
+ console2.log(
+ "CampaignInfo implementation deployed at:",
+ address(campaignInfo)
+ );
+ return address(campaignInfo);
+ }
+
+ function run() external {
+ uint256 deployerKey = vm.envUint("PRIVATE_KEY");
+ bool simulate = vm.envOr("SIMULATE", false);
+
+ if (!simulate) {
+ vm.startBroadcast(deployerKey);
+ }
+
+ address implementationAddress = deploy();
+
+ if (!simulate) {
+ vm.stopBroadcast();
+ }
+
+ console2.log("CAMPAIGN_INFO_ADDRESS", implementationAddress);
+ }
+}
diff --git a/script/DeployGlobalParams.s.sol b/script/DeployGlobalParams.s.sol
index 22e51ca3..185d3856 100644
--- a/script/DeployGlobalParams.s.sol
+++ b/script/DeployGlobalParams.s.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {GlobalParams} from "../src/GlobalParams.sol";
@@ -16,8 +16,8 @@ contract DeployGlobalParams is DeployBase {
function _deploy() internal returns (address) {
address deployer = vm.addr(vm.envUint("PRIVATE_KEY"));
- address token = vm.envOr("TEST_USD_ADDRESS", address(0));
- require(token != address(0), "TestUSD address must be set");
+ address token = vm.envOr("TOKEN_ADDRESS", address(0));
+ require(token != address(0), "TestToken address must be set");
return address(new GlobalParams(deployer, token, 200));
}
diff --git a/script/DeployTestToken.s.sol b/script/DeployTestToken.s.sol
new file mode 100644
index 00000000..93d6d072
--- /dev/null
+++ b/script/DeployTestToken.s.sol
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import {TestToken} from "../test/mocks/TestToken.sol";
+import {DeployBase} from "./lib/DeployBase.s.sol";
+
+contract DeployTestToken is DeployBase {
+ function deploy() public returns (address) {
+ return deployOrUse("TOKEN_ADDRESS", _deploy);
+ }
+
+ function _deploy() internal returns (address) {
+ string memory tokenName = vm.envOr("TOKEN_NAME", string("TestToken"));
+ string memory tokenSymbol = vm.envOr("TOKEN_SYMBOL", string("TST"));
+ return address(new TestToken(tokenName, tokenSymbol));
+ }
+
+ function run() external {
+ vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
+ deploy();
+ vm.stopBroadcast();
+ }
+}
diff --git a/script/DeployTestUSD.s.sol b/script/DeployTestUSD.s.sol
deleted file mode 100644
index 3a955e91..00000000
--- a/script/DeployTestUSD.s.sol
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.20;
-
-import {TestUSD} from "../src/TestUSD.sol";
-import {DeployBase} from "./lib/DeployBase.s.sol";
-
-contract DeployTestUSD is DeployBase {
- function deploy() public returns (address) {
- return deployOrUse("TEST_USD_ADDRESS", _deploy);
- }
-
- function _deploy() internal returns (address) {
- return address(new TestUSD());
- }
-
- function run() external {
- vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
- deploy();
- vm.stopBroadcast();
- }
-}
diff --git a/script/DeployTreasuryFactory.s.sol b/script/DeployTreasuryFactory.s.sol
index 068cb9ac..4689147f 100644
--- a/script/DeployTreasuryFactory.s.sol
+++ b/script/DeployTreasuryFactory.s.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {TreasuryFactory} from "../src/TreasuryFactory.sol";
@@ -19,4 +19,4 @@ contract DeployTreasuryFactory is DeployBase {
deploy(globalParams);
vm.stopBroadcast();
}
-}
\ No newline at end of file
+}
diff --git a/script/lib/DeployBase.s.sol b/script/lib/DeployBase.s.sol
index 14ed974b..e3b38fc7 100644
--- a/script/lib/DeployBase.s.sol
+++ b/script/lib/DeployBase.s.sol
@@ -1,7 +1,8 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "forge-std/Script.sol";
+import {Script} from "forge-std/Script.sol";
+import {console2} from "forge-std/console2.sol";
contract DeployBase is Script {
function deployOrUse(
diff --git a/src/CampaignInfo.sol b/src/CampaignInfo.sol
index d3b795fb..9dc4e9af 100644
--- a/src/CampaignInfo.sol
+++ b/src/CampaignInfo.sol
@@ -1,17 +1,17 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/proxy/Clones.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
-import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
+import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
+import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
+import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
-import "./interfaces/ICampaignInfo.sol";
-import "./interfaces/ICampaignData.sol";
-import "./interfaces/ICampaignTreasury.sol";
-import "./interfaces/IGlobalParams.sol";
-import "./utils/TimestampChecker.sol";
-import "./utils/AdminAccessChecker.sol";
-import "./utils/PausableCancellable.sol";
+import {ICampaignInfo} from "./interfaces/ICampaignInfo.sol";
+import {ICampaignData} from "./interfaces/ICampaignData.sol";
+import {ICampaignTreasury} from "./interfaces/ICampaignTreasury.sol";
+import {IGlobalParams} from "./interfaces/IGlobalParams.sol";
+import {TimestampChecker} from "./utils/TimestampChecker.sol";
+import {AdminAccessChecker} from "./utils/AdminAccessChecker.sol";
+import {PausableCancellable} from "./utils/PausableCancellable.sol";
/**
* @title CampaignInfo
@@ -28,31 +28,22 @@ contract CampaignInfo is
{
CampaignData private s_campaignData;
- mapping(bytes32 => bool) private s_selectedPlatformHash;
mapping(bytes32 => address) private s_platformTreasuryAddress;
mapping(bytes32 => uint256) private s_platformFeePercent;
+ mapping(bytes32 => bool) private s_isSelectedPlatform;
+ mapping(bytes32 => bool) private s_isApprovedPlatform;
mapping(bytes32 => bytes32) private s_platformData;
- bytes32[] private s_approvedplatformHash;
+ bytes32[] private s_approvedPlatformHashes;
function getApprovedPlatformHashes()
external
view
returns (bytes32[] memory)
{
- return s_approvedplatformHash;
+ return s_approvedPlatformHashes;
}
- /**
- * @dev Emitted when a platform is selected for the campaign.
- * @param platformHash The bytes32 identifier of the platform.
- * @param platformTreasury The address of the platform's treasury.
- */
- event CampaignInfoPlatformSelected(
- bytes32 indexed platformHash,
- address indexed platformTreasury
- );
-
/**
* @dev Emitted when the launch time of the campaign is updated.
* @param newLaunchTime The new launch time.
@@ -91,16 +82,6 @@ contract CampaignInfo is
address indexed platformTreasury
);
- /**
- * @dev Emitted when ownership of the contract is transferred.
- * @param previousOwner The address of the previous owner.
- * @param newOwner The address of the new owner.
- */
- event CampaignInfoOwnershipTransferred(
- address indexed previousOwner,
- address indexed newOwner
- );
-
/**
* @dev Emitted when an invalid platform update is attempted.
* @param platformHash The bytes32 identifier of the platform.
@@ -127,6 +108,12 @@ contract CampaignInfo is
*/
error CampaignInfoPlatformNotSelected(bytes32 platformHash);
+ /**
+ * @dev Emitted when a platform is already approved for the campaign.
+ * @param platformHash The bytes32 identifier of the platform.
+ */
+ error CampaignInfoPlatformAlreadyApproved(bytes32 platformHash);
+
constructor(address creator) Ownable(creator) {}
function initialize(
@@ -144,7 +131,7 @@ contract CampaignInfo is
for (uint256 i = 0; i < len; ++i) {
s_platformFeePercent[selectedPlatformHash[i]] = GLOBAL_PARAMS
.getPlatformFeePercent(selectedPlatformHash[i]);
- s_selectedPlatformHash[selectedPlatformHash[i]] = true;
+ s_isSelectedPlatform[selectedPlatformHash[i]] = true;
}
len = platformDataKey.length;
bool isValid;
@@ -182,7 +169,18 @@ contract CampaignInfo is
function checkIfPlatformSelected(
bytes32 platformHash
) public view override returns (bool) {
- return s_selectedPlatformHash[platformHash];
+ return s_isSelectedPlatform[platformHash];
+ }
+
+ /**
+ * @dev Check if a platform is already approved
+ * @param platformHash The bytes32 identifier of the platform.
+ * @return True if the platform is already approved, false otherwise.
+ */
+ function checkIfPlatformApproved(
+ bytes32 platformHash
+ ) public view returns (bool) {
+ return s_isApprovedPlatform[platformHash];
}
/**
@@ -208,8 +206,8 @@ contract CampaignInfo is
* @inheritdoc ICampaignInfo
*/
function getTotalRaisedAmount() external view override returns (uint256) {
- bytes32[] memory tempPlatforms = s_approvedplatformHash;
- uint256 length = s_approvedplatformHash.length;
+ bytes32[] memory tempPlatforms = s_approvedPlatformHashes;
+ uint256 length = s_approvedPlatformHashes.length;
uint256 amount;
address tempTreasury;
for (uint256 i = 0; i < length; i++) {
@@ -324,7 +322,13 @@ contract CampaignInfo is
*/
function transferOwnership(
address newOwner
- ) public override(ICampaignInfo, Ownable) onlyOwner whenNotPaused whenNotCancelled {
+ )
+ public
+ override(ICampaignInfo, Ownable)
+ onlyOwner
+ whenNotPaused
+ whenNotCancelled
+ {
super.transferOwnership(newOwner);
}
@@ -341,7 +345,7 @@ contract CampaignInfo is
whenNotPaused
whenNotCancelled
{
- if (launchTime < block.timestamp && getDeadline() <= launchTime) {
+ if (launchTime < block.timestamp || getDeadline() <= launchTime) {
revert CampaignInfoInvalidInput();
}
s_campaignData.launchTime = launchTime;
@@ -385,6 +389,7 @@ contract CampaignInfo is
if (goalAmount == 0) {
revert CampaignInfoInvalidInput();
}
+ s_campaignData.goalAmount = goalAmount;
emit CampaignInfoGoalAmountUpdated(goalAmount);
}
@@ -408,7 +413,17 @@ contract CampaignInfo is
if (!GLOBAL_PARAMS.checkIfPlatformIsListed(platformHash)) {
revert CampaignInfoInvalidPlatformUpdate(platformHash, selection);
}
- s_selectedPlatformHash[platformHash] = selection;
+
+ if (!selection && checkIfPlatformApproved(platformHash)) {
+ revert CampaignInfoPlatformAlreadyApproved(platformHash);
+ }
+ s_isSelectedPlatform[platformHash] = selection;
+ if (selection) {
+ s_platformFeePercent[platformHash] = GLOBAL_PARAMS
+ .getPlatformFeePercent(platformHash);
+ } else {
+ s_platformFeePercent[platformHash] = 0;
+ }
emit CampaignInfoSelectedPlatformUpdated(platformHash, selection);
}
@@ -453,8 +468,13 @@ contract CampaignInfo is
if (!selected) {
revert CampaignInfoPlatformNotSelected(platformHash);
}
+ if (s_isApprovedPlatform[platformHash]) {
+ revert CampaignInfoPlatformAlreadyApproved(platformHash);
+ }
s_platformTreasuryAddress[platformHash] = platformTreasuryAddress;
- s_approvedplatformHash.push(platformHash);
+ s_approvedPlatformHashes.push(platformHash);
+ s_isApprovedPlatform[platformHash] = true;
+
emit CampaignInfoPlatformInfoUpdated(
platformHash,
platformTreasuryAddress
diff --git a/src/CampaignInfoFactory.sol b/src/CampaignInfoFactory.sol
index f5d554f4..8342956c 100644
--- a/src/CampaignInfoFactory.sol
+++ b/src/CampaignInfoFactory.sol
@@ -1,12 +1,12 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/proxy/Clones.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
-import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
+import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
+import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
+import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
-import "./interfaces/IGlobalParams.sol";
-import "./interfaces/ICampaignInfoFactory.sol";
+import {IGlobalParams} from "./interfaces/IGlobalParams.sol";
+import {ICampaignInfoFactory} from "./interfaces/ICampaignInfoFactory.sol";
/**
* @title CampaignInfoFactory
@@ -82,7 +82,7 @@ contract CampaignInfoFactory is Initializable, ICampaignInfoFactory, Ownable {
CampaignData calldata campaignData
) external override {
if (
- campaignData.launchTime < block.timestamp &&
+ campaignData.launchTime < block.timestamp ||
campaignData.deadline <= campaignData.launchTime
) {
revert CampaignInfoFactoryInvalidInput();
diff --git a/src/GlobalParams.sol b/src/GlobalParams.sol
index b228e0a5..202951c4 100644
--- a/src/GlobalParams.sol
+++ b/src/GlobalParams.sol
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/access/Ownable.sol";
+import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
-import "./interfaces/IGlobalParams.sol";
-import "./utils/Counters.sol";
+import {IGlobalParams} from "./interfaces/IGlobalParams.sol";
+import {Counters} from "./utils/Counters.sol";
/**
* @title GlobalParams
@@ -257,17 +257,8 @@ contract GlobalParams is IGlobalParams, Ownable {
*/
function getPlatformDataOwner(
bytes32 platformDataKey
- )
- external
- view
- override
- platformIsListed(platformHash)
- returns (bytes32 platformHash)
- {
+ ) external view override returns (bytes32 platformHash) {
platformHash = s_platformDataOwner[platformDataKey];
- if (platformHash == ZERO_BYTES) {
- revert GlobalParamsInvalidInput();
- }
}
/**
@@ -300,7 +291,7 @@ contract GlobalParams is IGlobalParams, Ownable {
address platformAdminAddress,
uint256 platformFeePercent
) external onlyOwner notAddressZero(platformAdminAddress) {
- if (platformHash == ZERO_BYTES || platformAdminAddress == address(0)) {
+ if (platformHash == ZERO_BYTES) {
revert GlobalParamsInvalidInput();
}
if (s_platformIsListed[platformHash]) {
@@ -344,12 +335,9 @@ contract GlobalParams is IGlobalParams, Ownable {
if (platformDataKey == ZERO_BYTES) {
revert GlobalParamsInvalidInput();
}
- if (s_platformData[platformDataKey] != false) {
+ if (s_platformData[platformDataKey]) {
revert GlobalParamsPlatformDataAlreadySet();
}
- if (s_platformDataOwner[platformDataKey] == platformHash) {
- revert GlobalParamsPlatformDataSlotTaken();
- }
s_platformData[platformDataKey] = true;
s_platformDataOwner[platformDataKey] = platformHash;
emit PlatformDataAdded(platformHash, platformDataKey);
@@ -367,7 +355,7 @@ contract GlobalParams is IGlobalParams, Ownable {
if (platformDataKey == ZERO_BYTES) {
revert GlobalParamsInvalidInput();
}
- if (s_platformData[platformDataKey] == false) {
+ if (!s_platformData[platformDataKey]) {
revert GlobalParamsPlatformDataNotSet();
}
s_platformData[platformDataKey] = false;
diff --git a/src/TestUSD.sol b/src/TestUSD.sol
deleted file mode 100644
index 19cf382e..00000000
--- a/src/TestUSD.sol
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.20;
-
-import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
-
-/**
- * @title TestUSD
- * @notice A test token `tUSD` which is used in the tests.
- */
-contract TestUSD is ERC20, Ownable {
- constructor() ERC20("testUSD", "tUSD") Ownable(msg.sender) {}
-
- /**
- * @notice Mints testUSD token.
- * @param to The token receivers address.
- * @param amount The amount of tokens to mint.
- */
- function mint(address to, uint256 amount) public onlyOwner {
- _mint(to, amount);
- }
-}
diff --git a/src/TreasuryFactory.sol b/src/TreasuryFactory.sol
index e989b8ad..44f05280 100644
--- a/src/TreasuryFactory.sol
+++ b/src/TreasuryFactory.sol
@@ -1,15 +1,14 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/proxy/Clones.sol";
+import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
-import "./CampaignInfo.sol";
-import "./interfaces/ITreasuryFactory.sol";
-import "./utils/AdminAccessChecker.sol";
+import {ITreasuryFactory} from "./interfaces/ITreasuryFactory.sol";
+import {IGlobalParams, AdminAccessChecker} from "./utils/AdminAccessChecker.sol";
contract TreasuryFactory is ITreasuryFactory, AdminAccessChecker {
- mapping(bytes32 => mapping(uint256 => address)) implementationMap;
- mapping(address => bool) approvedImplementations;
+ mapping(bytes32 => mapping(uint256 => address)) private implementationMap;
+ mapping(address => bool) private approvedImplementations;
error TreasuryFactoryUnauthorized();
error TreasuryFactoryInvalidKey();
diff --git a/src/interfaces/ICampaignData.sol b/src/interfaces/ICampaignData.sol
index cab7c378..abf5e0ac 100644
--- a/src/interfaces/ICampaignData.sol
+++ b/src/interfaces/ICampaignData.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
diff --git a/src/interfaces/ICampaignInfo.sol b/src/interfaces/ICampaignInfo.sol
index 509769b1..43771b79 100644
--- a/src/interfaces/ICampaignInfo.sol
+++ b/src/interfaces/ICampaignInfo.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
@@ -122,6 +122,7 @@ interface ICampaignInfo {
/**
* @notice Updates the selection status of a platform for the campaign.
+ * @dev It can only be called for a platform if its not approved i.e. the platform treasury is not deployed
* @param platformHash The bytes32 identifier of the platform.
* @param selection The new selection status (true or false).
*/
diff --git a/src/interfaces/ICampaignInfoFactory.sol b/src/interfaces/ICampaignInfoFactory.sol
index 6481dfae..f8b53c35 100644
--- a/src/interfaces/ICampaignInfoFactory.sol
+++ b/src/interfaces/ICampaignInfoFactory.sol
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "./ICampaignData.sol";
+import {ICampaignData} from "./ICampaignData.sol";
/**
* @title ICampaignInfoFactory
@@ -18,11 +18,10 @@ interface ICampaignInfoFactory is ICampaignData {
address indexed campaignInfoAddress
);
- /**
+ /**
* @notice Emitted when the campaign after creation is initialized.
- */
- event CampaignInfoFactoryCampaignInitialized(
- );
+ */
+ event CampaignInfoFactoryCampaignInitialized();
/**
* @notice Creates a new campaign information contract.
@@ -46,7 +45,5 @@ interface ICampaignInfoFactory is ICampaignData {
* @notice Updates the campaign implementation address.
* @param newImplementation The address of the camapaignInfo implementation contract.
*/
- function updateImplementation(
- address newImplementation
- ) external;
+ function updateImplementation(address newImplementation) external;
}
diff --git a/src/interfaces/ICampaignTreasury.sol b/src/interfaces/ICampaignTreasury.sol
index 578f3df2..2b6c2b67 100644
--- a/src/interfaces/ICampaignTreasury.sol
+++ b/src/interfaces/ICampaignTreasury.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
@@ -26,13 +26,13 @@ interface ICampaignTreasury {
* @notice Retrieves the platform identifier associated with the treasury.
* @return The platform identifier as a bytes32 value.
*/
- function getplatformHash() external view returns (bytes32);
+ function getPlatformHash() external view returns (bytes32);
/**
* @notice Retrieves the platform fee percentage for the treasury.
* @return The platform fee percentage as a uint256 value.
*/
- function getplatformFeePercent() external view returns (uint256);
+ function getPlatformFeePercent() external view returns (uint256);
/**
* @notice Retrieves the total raised amount in the treasury.
diff --git a/src/interfaces/IGlobalParams.sol b/src/interfaces/IGlobalParams.sol
index fda1b617..4bc1f7dc 100644
--- a/src/interfaces/IGlobalParams.sol
+++ b/src/interfaces/IGlobalParams.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
diff --git a/src/interfaces/IItem.sol b/src/interfaces/IItem.sol
index e6971d16..95a1aad8 100644
--- a/src/interfaces/IItem.sol
+++ b/src/interfaces/IItem.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
diff --git a/src/interfaces/IReward.sol b/src/interfaces/IReward.sol
index 890aa12b..92a3212f 100644
--- a/src/interfaces/IReward.sol
+++ b/src/interfaces/IReward.sol
@@ -1,11 +1,11 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title IReward
* @notice An interface for managing rewards in a campaign.
*/
-interface IReward {
+interface IReward {
struct Reward {
uint256 rewardValue;
bool isRewardTier;
diff --git a/src/interfaces/ITreasuryFactory.sol b/src/interfaces/ITreasuryFactory.sol
index dfd8242b..ca3f4b74 100644
--- a/src/interfaces/ITreasuryFactory.sol
+++ b/src/interfaces/ITreasuryFactory.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
diff --git a/src/treasuries/AllOrNothing.sol b/src/treasuries/AllOrNothing.sol
index 75046efc..2a400a9e 100644
--- a/src/treasuries/AllOrNothing.sol
+++ b/src/treasuries/AllOrNothing.sol
@@ -1,13 +1,15 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
-import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
+import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
+import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
+import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
-import "../utils/Counters.sol";
-import "../utils/TimestampChecker.sol";
-import "../utils/BaseTreasury.sol";
-import "../interfaces/IReward.sol";
+import {Counters} from "../utils/Counters.sol";
+import {TimestampChecker} from "../utils/TimestampChecker.sol";
+import {ICampaignTreasury} from "../interfaces/ICampaignTreasury.sol";
+import {BaseTreasury} from "../utils/BaseTreasury.sol";
+import {IReward} from "../interfaces/IReward.sol";
/**
* @title AllOrNothing
@@ -384,10 +386,10 @@ contract AllOrNothing is
uint256 totalAmount = pledgeAmount + shippingFee;
TOKEN.safeTransferFrom(backer, address(this), totalAmount);
s_tokenIdCounter.increment();
- _safeMint(backer, tokenId, abi.encodePacked(backer, reward));
s_tokenToPledgedAmount[tokenId] = pledgeAmount;
s_tokenToTotalCollectedAmount[tokenId] = totalAmount;
s_pledgedAmount += pledgeAmount;
+ _safeMint(backer, tokenId, abi.encodePacked(backer, reward, rewards));
emit Receipt(
backer,
reward,
diff --git a/src/utils/AdminAccessChecker.sol b/src/utils/AdminAccessChecker.sol
index c798e730..7c025282 100644
--- a/src/utils/AdminAccessChecker.sol
+++ b/src/utils/AdminAccessChecker.sol
@@ -1,7 +1,7 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "../interfaces/IGlobalParams.sol";
+import {IGlobalParams} from "../interfaces/IGlobalParams.sol";
/**
* @title AdminAccessChecker
diff --git a/src/utils/BaseTreasury.sol b/src/utils/BaseTreasury.sol
index 33bb602b..78abe289 100644
--- a/src/utils/BaseTreasury.sol
+++ b/src/utils/BaseTreasury.sol
@@ -1,14 +1,12 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
-import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
+import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
+import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
-import "../interfaces/ICampaignInfo.sol";
-import "../interfaces/ICampaignTreasury.sol";
-import "./CampaignAccessChecker.sol";
-import "./PausableCancellable.sol";
+import {ICampaignTreasury} from "../interfaces/ICampaignTreasury.sol";
+import {CampaignAccessChecker} from "./CampaignAccessChecker.sol";
+import {PausableCancellable} from "./PausableCancellable.sol";
/**
* @title BaseTreasury
@@ -23,6 +21,7 @@ abstract contract BaseTreasury is
PausableCancellable
{
using SafeERC20 for IERC20;
+
bytes32 internal constant ZERO_BYTES =
0x0000000000000000000000000000000000000000000000000000000000000000;
uint256 internal constant PERCENT_DIVIDER = 10000;
@@ -30,7 +29,6 @@ abstract contract BaseTreasury is
bytes32 internal PLATFORM_HASH;
uint256 internal PLATFORM_FEE_PERCENT;
IERC20 internal TOKEN;
- ICampaignInfo internal CAMPAIGN_INFO;
uint256 internal s_pledgedAmount;
bool internal s_feesDisbursed;
@@ -80,7 +78,6 @@ abstract contract BaseTreasury is
) internal {
__CampaignAccessChecker_init(infoAddress);
PLATFORM_HASH = platformHash;
- CAMPAIGN_INFO = ICampaignInfo(infoAddress);
TOKEN = IERC20(INFO.getTokenAddress());
PLATFORM_FEE_PERCENT = INFO.getPlatformFeePercent(platformHash);
}
@@ -101,14 +98,14 @@ abstract contract BaseTreasury is
/**
* @inheritdoc ICampaignTreasury
*/
- function getplatformHash() external view override returns (bytes32) {
+ function getPlatformHash() external view override returns (bytes32) {
return PLATFORM_HASH;
}
/**
* @inheritdoc ICampaignTreasury
*/
- function getplatformFeePercent() external view override returns (uint256) {
+ function getPlatformFeePercent() external view override returns (uint256) {
return PLATFORM_FEE_PERCENT;
}
diff --git a/src/utils/CampaignAccessChecker.sol b/src/utils/CampaignAccessChecker.sol
index c292bef6..060cca68 100644
--- a/src/utils/CampaignAccessChecker.sol
+++ b/src/utils/CampaignAccessChecker.sol
@@ -1,8 +1,8 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "../interfaces/ICampaignInfo.sol";
-import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
+import {ICampaignInfo} from "../interfaces/ICampaignInfo.sol";
+import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
/**
* @title CampaignAccessChecker
@@ -22,7 +22,6 @@ abstract contract CampaignAccessChecker {
* @dev Constructor to initialize the contract with the address of the campaign information contract.
* @param campaignInfo The address of the ICampaignInfo contract.
*/
-
function __CampaignAccessChecker_init(address campaignInfo) internal {
INFO = ICampaignInfo(campaignInfo);
}
diff --git a/src/utils/FiatEnabled.sol b/src/utils/FiatEnabled.sol
index 208ca91a..85d98f62 100644
--- a/src/utils/FiatEnabled.sol
+++ b/src/utils/FiatEnabled.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
diff --git a/src/utils/ItemRegistry.sol b/src/utils/ItemRegistry.sol
index 63f06100..0e6f4282 100644
--- a/src/utils/ItemRegistry.sol
+++ b/src/utils/ItemRegistry.sol
@@ -1,8 +1,9 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
-import "@openzeppelin/contracts/utils/Context.sol";
-import "../interfaces/IItem.sol";
+import {Context} from "@openzeppelin/contracts/utils/Context.sol";
+
+import {IItem} from "../interfaces/IItem.sol";
/**
* @title ItemRegistry
@@ -18,7 +19,7 @@ contract ItemRegistry is IItem, Context {
* @param item The item details including actual weight, dimensions, category, and declared currency.
*/
event ItemAdded(address indexed owner, bytes32 indexed itemId, Item item);
-
+
/**
* @dev Thrown when the input arrays have mismatched lengths.
*/
@@ -63,4 +64,4 @@ contract ItemRegistry is IItem, Context {
emit ItemAdded(_msgSender(), itemId, item);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/utils/PausableCancellable.sol b/src/utils/PausableCancellable.sol
index 6c65c268..db0994d0 100644
--- a/src/utils/PausableCancellable.sol
+++ b/src/utils/PausableCancellable.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title PausableCancellable
diff --git a/src/utils/TimestampChecker.sol b/src/utils/TimestampChecker.sol
index e5170999..7ae687f7 100644
--- a/src/utils/TimestampChecker.sol
+++ b/src/utils/TimestampChecker.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
@@ -63,7 +63,7 @@ abstract contract TimestampChecker {
uint256 inputTime
) internal view virtual {
uint256 currentTime = block.timestamp;
- if (currentTime > inputTime) {
+ if (currentTime >= inputTime) {
revert CurrentTimeIsGreater(inputTime, currentTime);
}
}
@@ -76,7 +76,7 @@ abstract contract TimestampChecker {
uint256 inputTime
) internal view virtual {
uint256 currentTime = block.timestamp;
- if (currentTime < inputTime) {
+ if (currentTime <= inputTime) {
revert CurrentTimeIsLess(inputTime, currentTime);
}
}
diff --git a/test/foundry/Base.t.sol b/test/foundry/Base.t.sol
index a1c21181..ad771340 100644
--- a/test/foundry/Base.t.sol
+++ b/test/foundry/Base.t.sol
@@ -1,10 +1,10 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import {Users} from "./utils/Types.sol";
import {Defaults} from "./utils/Defaults.sol";
-import {TestUSD} from "src/TestUSD.sol";
+import {TestToken} from "../mocks/TestToken.sol";
import {GlobalParams} from "src/GlobalParams.sol";
import {CampaignInfoFactory} from "src/CampaignInfoFactory.sol";
import {CampaignInfo} from "src/CampaignInfo.sol";
@@ -17,7 +17,7 @@ abstract contract Base_Test is Test, Defaults {
Users internal users;
//Test Contracts
- TestUSD internal testUSD;
+ TestToken internal testToken;
GlobalParams internal globalParams;
CampaignInfoFactory internal campaignInfoFactory;
TreasuryFactory internal treasuryFactory;
@@ -40,16 +40,19 @@ abstract contract Base_Test is Test, Defaults {
vm.startPrank(users.contractOwner);
// Deploy the base test contracts.
- testUSD = new TestUSD();
+ testToken = new TestToken(tokenName, tokenSymbol);
globalParams = new GlobalParams(
users.protocolAdminAddress,
- address(testUSD),
+ address(testToken),
PROTOCOL_FEE_PERCENT
);
campaignInfo = new CampaignInfo(address(this));
console.log("CampaignInfo address: ", address(campaignInfo));
- campaignInfoFactory = new CampaignInfoFactory(globalParams, address(campaignInfo));
+ campaignInfoFactory = new CampaignInfoFactory(
+ globalParams,
+ address(campaignInfo)
+ );
treasuryFactory = new TreasuryFactory(globalParams);
//Initialize campaignInfoFactory
@@ -60,13 +63,13 @@ abstract contract Base_Test is Test, Defaults {
allOrNothingImplementation = new AllOrNothing();
//Mint token to the backer
- testUSD.mint(users.backer1Address, TOKEN_MINT_AMOUNT);
- testUSD.mint(users.backer2Address, TOKEN_MINT_AMOUNT);
+ testToken.mint(users.backer1Address, TOKEN_MINT_AMOUNT);
+ testToken.mint(users.backer2Address, TOKEN_MINT_AMOUNT);
vm.stopPrank();
// Label the base test contracts.
- vm.label({account: address(testUSD), newLabel: "TestUSD"});
+ vm.label({account: address(testToken), newLabel: "TestToken"});
vm.label({
account: address(globalParams),
newLabel: "Global Parameter"
diff --git a/test/foundry/integration/AllOrNothing/AllOrNothing.t.sol b/test/foundry/integration/AllOrNothing/AllOrNothing.t.sol
index 38eba557..2b12aebb 100644
--- a/test/foundry/integration/AllOrNothing/AllOrNothing.t.sol
+++ b/test/foundry/integration/AllOrNothing/AllOrNothing.t.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Base_Test} from "../../Base.t.sol";
@@ -10,19 +10,35 @@ import {CampaignInfo} from "src/CampaignInfo.sol";
import {IReward} from "src/interfaces/IReward.sol";
import {LogDecoder} from "../../utils/LogDecoder.sol";
-/// @notice Common testing logic needed by all AllOrNothing integration tests.
+/**
+ * @title AllOrNothing Integration Test Shared Contract
+ * @notice Common testing logic needed by all AllOrNothing integration tests.
+ * @dev Abstract contract that provides shared setup and helper functions for AllOrNothing treasury testing.
+ * Handles platform enrollment, treasury implementation registration, campaign creation, and treasury deployment.
+ * Also provides utility functions for pledging, refunding, fee disbursement, and withdrawals.
+ */
abstract contract AllOrNothing_Integration_Shared_Test is
IReward,
LogDecoder,
Base_Test
{
+ /// @dev Address of the created campaign contract
address campaignAddress;
+
+ /// @dev Address of the deployed treasury contract
address treasuryAddress;
+
+ /// @dev Instance of the AllOrNothing treasury contract
AllOrNothing internal allOrNothing;
+ /// @dev Token ID for pledges that include rewards
uint256 pledgeForARewardTokenId;
- /// @dev Initial dependent functions setup included for AllOrNothing Integration Tests.
+ /**
+ * @notice Initial setup for AllOrNothing integration tests
+ * @dev Performs the complete setup sequence: platform enrollment, treasury registration,
+ * campaign creation, and treasury deployment. Called by inheriting test contracts.
+ */
function setUp() public virtual override {
super.setUp();
console.log("setUp: enlistPlatform");
@@ -31,9 +47,11 @@ abstract contract AllOrNothing_Integration_Shared_Test is
enlistPlatform(PLATFORM_1_HASH);
console.log("enlisted platform");
+ //Register Treasury Implementation
registerTreasuryImplementation(PLATFORM_1_HASH);
console.log("registered treasury");
+ //Approve Treasury Implementation
approveTreasuryImplementation(PLATFORM_1_HASH);
console.log("approved treasury");
@@ -47,8 +65,9 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements enlistPlatform helper function.
- * @param platformHash The platform bytes.
+ * @notice Enlists a platform in the protocol
+ * @dev Called by protocol admin to register a new platform with specified fee structure
+ * @param platformHash The unique identifier hash for the platform
*/
function enlistPlatform(bytes32 platformHash) internal {
vm.startPrank(users.protocolAdminAddress);
@@ -60,6 +79,11 @@ abstract contract AllOrNothing_Integration_Shared_Test is
vm.stopPrank();
}
+ /**
+ * @notice Registers a treasury implementation for a platform
+ * @dev Called by platform admin to register AllOrNothing treasury implementation
+ * @param platformHash The platform identifier to register the treasury for
+ */
function registerTreasuryImplementation(bytes32 platformHash) internal {
vm.startPrank(users.platform1AdminAddress);
treasuryFactory.registerTreasuryImplementation(
@@ -70,6 +94,11 @@ abstract contract AllOrNothing_Integration_Shared_Test is
vm.stopPrank();
}
+ /**
+ * @notice Approves a registered treasury implementation
+ * @dev Called by protocol admin to approve a platform's treasury implementation
+ * @param platformHash The platform identifier whose treasury implementation to approve
+ */
function approveTreasuryImplementation(bytes32 platformHash) internal {
vm.startPrank(users.protocolAdminAddress);
treasuryFactory.approveTreasuryImplementation(platformHash, 0);
@@ -77,8 +106,9 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements createCampaign helper function. It creates new campaign info contract
- * @param platformHash The platform bytes.
+ * @notice Creates a new campaign for testing
+ * @dev Creates a campaign info contract and extracts the campaign address from emitted events
+ * @param platformHash The platform identifier to create the campaign on
*/
function createCampaign(bytes32 platformHash) internal {
bytes32 identifierHash = keccak256(abi.encodePacked(platformHash));
@@ -114,7 +144,9 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements deploy helper function. It deploys treasury contract.
+ * @notice Deploys a treasury contract for the created campaign
+ * @dev Deploys AllOrNothing treasury and extracts the treasury address from emitted events
+ * @param platformHash The platform identifier to deploy the treasury for
*/
function deploy(bytes32 platformHash) internal {
vm.startPrank(users.platform1AdminAddress);
@@ -141,6 +173,14 @@ abstract contract AllOrNothing_Integration_Shared_Test is
allOrNothing = AllOrNothing(treasuryAddress);
}
+ /**
+ * @notice Adds rewards to a treasury contract
+ * @dev Helper function to add reward tiers to an AllOrNothing treasury
+ * @param caller The address that will call the addRewards function
+ * @param treasury The treasury contract address
+ * @param rewardNames Array of reward names/identifiers
+ * @param rewards Array of reward structs containing reward details
+ */
function addRewards(
address caller,
address treasury,
@@ -153,15 +193,24 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements pledgeForAReward helper function.
+ * @notice Simulates pledging for a specific reward
+ * @dev Creates a pledge with reward selection and captures the receipt event
+ * @param caller The address making the pledge
+ * @param warpTime The block timestamp to warp to
+ * @param allOrNothingAddress The treasury contract address
+ * @param pledgeAmount The amount to pledge (automatically calculated from reward)
+ * @param shippingFee The shipping fee for the reward
+ * @param rewardName The identifier of the reward being pledged for
+ * @return logs The transaction logs
+ * @return tokenId The NFT token ID representing the pledge
+ * @return rewards Array of reward names associated with the pledge
*/
function pledgeForAReward(
address caller,
- address token,
+ uint256 warpTime,
address allOrNothingAddress,
uint256 pledgeAmount,
uint256 shippingFee,
- uint256 launchTime,
bytes32 rewardName
)
internal
@@ -172,10 +221,10 @@ abstract contract AllOrNothing_Integration_Shared_Test is
)
{
vm.startPrank(caller);
+ vm.warp(warpTime);
vm.recordLogs();
- testUSD.approve(allOrNothingAddress, pledgeAmount + shippingFee);
- vm.warp(launchTime);
+ testToken.approve(allOrNothingAddress, pledgeAmount + shippingFee);
bytes32[] memory reward = new bytes32[](1);
reward[0] = rewardName;
@@ -194,7 +243,6 @@ abstract contract AllOrNothing_Integration_Shared_Test is
allOrNothingAddress
);
- // (, tokenId, rewards) = abi.decode(data, (uint256, uint256, bytes32[]));
(, , tokenId, rewards) = abi.decode(
data,
(uint256, uint256, uint256, bytes32[])
@@ -204,20 +252,26 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements pledgeWithoutAReward helper function.
+ * @notice Simulates pledging without selecting a reward
+ * @dev Creates a pledge without reward selection and captures the receipt event
+ * @param caller The address making the pledge
+ * @param warpTime The block timestamp to warp to
+ * @param allOrNothingAddress The treasury contract address
+ * @param pledgeAmount The amount to pledge
+ * @return logs The transaction logs
+ * @return tokenId The NFT token ID representing the pledge
*/
function pledgeWithoutAReward(
address caller,
- address token,
+ uint256 warpTime,
address allOrNothingAddress,
- uint256 pledgeAmount,
- uint256 launchTime
+ uint256 pledgeAmount
) internal returns (Vm.Log[] memory logs, uint256 tokenId) {
vm.startPrank(caller);
+ vm.warp(warpTime);
vm.recordLogs();
- testUSD.approve(allOrNothingAddress, pledgeAmount);
- vm.warp(launchTime);
+ testToken.approve(allOrNothingAddress, pledgeAmount);
AllOrNothing(allOrNothingAddress).pledgeWithoutAReward(
caller,
@@ -241,10 +295,20 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements claimRefund helper function.
+ * @notice Simulates claiming a refund for a failed campaign
+ * @dev Claims refund for a pledge token and captures the refund event
+ * @param caller The address claiming the refund
+ * @param warpTime The block timestamp to warp to
+ * @param allOrNothingAddress The treasury contract address
+ * @param tokenId The pledge token ID to refund
+ * @return logs The transaction logs
+ * @return refundedTokenId The token ID that was refunded
+ * @return refundAmount The amount refunded
+ * @return claimer The address that claimed the refund
*/
function claimRefund(
address caller,
+ uint256 warpTime,
address allOrNothingAddress,
uint256 tokenId
)
@@ -257,6 +321,7 @@ abstract contract AllOrNothing_Integration_Shared_Test is
)
{
vm.startPrank(caller);
+ vm.warp(warpTime);
vm.recordLogs();
AllOrNothing(allOrNothingAddress).claimRefund(tokenId);
@@ -278,7 +343,13 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements disburseFees helper function.
+ * @notice Simulates fee disbursement for a successful campaign
+ * @dev Disburses protocol and platform fees and captures the disbursement event
+ * @param allOrNothingAddress The treasury contract address
+ * @param warpTime The block timestamp to warp to
+ * @return logs The transaction logs
+ * @return protocolShare The amount allocated to protocol fees
+ * @return platformShare The amount allocated to platform fees
*/
function disburseFees(
address allOrNothingAddress,
@@ -308,7 +379,13 @@ abstract contract AllOrNothing_Integration_Shared_Test is
}
/**
- * @notice Implements withdraw helper function.
+ * @notice Simulates withdrawal of funds from a successful campaign
+ * @dev Withdraws remaining funds to campaign creator and captures the withdrawal event
+ * @param allOrNothingAddress The treasury contract address
+ * @param warpTime The block timestamp to warp to
+ * @return logs The transaction logs
+ * @return to The address that received the withdrawal
+ * @return amount The amount withdrawn
*/
function withdraw(
address allOrNothingAddress,
@@ -336,4 +413,92 @@ abstract contract AllOrNothing_Integration_Shared_Test is
return (logs, to, amount);
}
+
+ /**
+ * @notice Removes a reward from a treasury contract
+ * @dev Helper function to remove a reward from an AllOrNothing treasury
+ * @param caller The address that will call the removeReward function
+ * @param treasury The treasury contract address
+ * @param rewardName The name of the reward to remove
+ * @return logs The transaction logs
+ */
+ function removeReward(
+ address caller,
+ address treasury,
+ bytes32 rewardName
+ ) internal returns (Vm.Log[] memory logs) {
+ vm.startPrank(caller);
+ vm.recordLogs();
+
+ AllOrNothing(treasury).removeReward(rewardName);
+
+ logs = vm.getRecordedLogs();
+ vm.stopPrank();
+ }
+
+ /**
+ * @notice Pauses a treasury contract
+ * @dev Helper function to pause an AllOrNothing treasury
+ * @param caller The address that will call the pauseTreasury function
+ * @param treasury The treasury contract address
+ * @param reason The reason for pausing
+ * @return logs The transaction logs
+ */
+ function pauseTreasury(
+ address caller,
+ address treasury,
+ bytes32 reason
+ ) internal returns (Vm.Log[] memory logs) {
+ vm.startPrank(caller);
+ vm.recordLogs();
+
+ AllOrNothing(treasury).pauseTreasury(reason);
+
+ logs = vm.getRecordedLogs();
+ vm.stopPrank();
+ }
+
+ /**
+ * @notice Unpauses a treasury contract
+ * @dev Helper function to unpause an AllOrNothing treasury
+ * @param caller The address that will call the unpauseTreasury function
+ * @param treasury The treasury contract address
+ * @param reason The reason for unpausing
+ * @return logs The transaction logs
+ */
+ function unpauseTreasury(
+ address caller,
+ address treasury,
+ bytes32 reason
+ ) internal returns (Vm.Log[] memory logs) {
+ vm.startPrank(caller);
+ vm.recordLogs();
+
+ AllOrNothing(treasury).unpauseTreasury(reason);
+
+ logs = vm.getRecordedLogs();
+ vm.stopPrank();
+ }
+
+ /**
+ * @notice Cancels a treasury contract
+ * @dev Helper function to cancel an AllOrNothing treasury
+ * @param caller The address that will call the cancelTreasury function
+ * @param treasury The treasury contract address
+ * @param reason The reason for cancellation
+ * @return logs The transaction logs
+ */
+ function cancelTreasury(
+ address caller,
+ address treasury,
+ bytes32 reason
+ ) internal returns (Vm.Log[] memory logs) {
+ vm.startPrank(caller);
+ vm.recordLogs();
+
+ AllOrNothing(treasury).cancelTreasury(reason);
+
+ logs = vm.getRecordedLogs();
+ vm.stopPrank();
+ }
}
diff --git a/test/foundry/integration/AllOrNothing/AllOrNothingFunction.t.sol b/test/foundry/integration/AllOrNothing/AllOrNothingFunction.t.sol
index c5f0738a..fef07b0d 100644
--- a/test/foundry/integration/AllOrNothing/AllOrNothingFunction.t.sol
+++ b/test/foundry/integration/AllOrNothing/AllOrNothingFunction.t.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./AllOrNothing.t.sol";
@@ -10,9 +10,22 @@ import {Constants} from "../../utils/Constants.sol";
import {Users} from "../../utils/Types.sol";
import {IReward} from "src/interfaces/IReward.sol";
+/**
+ * @title AllOrNothing Function Integration Test Contract
+ * @notice Comprehensive integration tests for AllOrNothing treasury contract functionality
+ * @dev Inherits from AllOrNothing_Integration_Shared_Test to access common setup and utilities.
+ * Tests cover the full lifecycle of campaign operations including reward setup, pledging,
+ * refund claims, fee disbursement, and fund withdrawal scenarios.
+ */
contract AllOrNothingFunction_Integration_Shared_Test is
AllOrNothing_Integration_Shared_Test
{
+ /**
+ * @notice Tests the addRewards functionality
+ * @dev Verifies that rewards can be properly added to the treasury contract and that
+ * all reward properties are stored correctly including values, tiers, items, and quantities.
+ * Tests multiple rewards with different configurations to ensure proper storage and retrieval.
+ */
function test_addRewards() external {
addRewards(
users.creator1Address,
@@ -49,6 +62,289 @@ contract AllOrNothingFunction_Integration_Shared_Test is
assertEq(REWARDS[2].itemId.length, resultReward3.itemId.length);
}
+ /**
+ * @notice Tests the removeReward functionality
+ * @dev Verifies that rewards can be properly removed from the treasury contract and that
+ * the reward is no longer accessible after removal. Ensures the RewardRemoved event
+ * is emitted correctly and attempts to access removed rewards result in reverts.
+ */
+ function test_removeReward() external {
+ addRewards(
+ users.creator1Address,
+ address(allOrNothing),
+ REWARD_NAMES,
+ REWARDS
+ );
+
+ // Verify reward exists before removal
+ Reward memory existingReward = allOrNothing.getReward(REWARD_NAMES[0]);
+ assertEq(existingReward.rewardValue, REWARDS[0].rewardValue);
+
+ // Remove the reward using helper function
+ Vm.Log[] memory logs = removeReward(
+ users.creator1Address,
+ address(allOrNothing),
+ REWARD_NAMES[0]
+ );
+
+ // For indexed parameters, we need to check topics
+ (bytes32[] memory topics, ) = decodeTopicsAndData(
+ logs,
+ "RewardRemoved(bytes32)",
+ address(allOrNothing)
+ );
+ assertEq(topics[1], REWARD_NAMES[0], "Removed reward name should match");
+
+ // Verify reward no longer exists (should revert)
+ vm.expectRevert();
+ allOrNothing.getReward(REWARD_NAMES[0]);
+ }
+
+ /**
+ * @notice Tests the getReward functionality
+ * @dev Verifies that reward details can be properly retrieved from the treasury contract.
+ * Tests retrieval of all reward properties including values, tier flags, item arrays,
+ * and validates that non-existent rewards cause appropriate reverts.
+ */
+ function test_getReward() external {
+ addRewards(
+ users.creator1Address,
+ address(allOrNothing),
+ REWARD_NAMES,
+ REWARDS
+ );
+
+ // Test getting each reward
+ for (uint i = 0; i < REWARD_NAMES.length; i++) {
+ Reward memory retrievedReward = allOrNothing.getReward(REWARD_NAMES[i]);
+
+ assertEq(retrievedReward.rewardValue, REWARDS[i].rewardValue, "Reward value mismatch");
+ assertEq(retrievedReward.isRewardTier, REWARDS[i].isRewardTier, "Reward tier flag mismatch");
+ assertEq(retrievedReward.itemId.length, REWARDS[i].itemId.length, "Item ID array length mismatch");
+ assertEq(retrievedReward.itemValue.length, REWARDS[i].itemValue.length, "Item value array length mismatch");
+ assertEq(retrievedReward.itemQuantity.length, REWARDS[i].itemQuantity.length, "Item quantity array length mismatch");
+
+ // Check array contents
+ for (uint j = 0; j < retrievedReward.itemId.length; j++) {
+ assertEq(retrievedReward.itemId[j], REWARDS[i].itemId[j], "Item ID mismatch");
+ assertEq(retrievedReward.itemValue[j], REWARDS[i].itemValue[j], "Item value mismatch");
+ assertEq(retrievedReward.itemQuantity[j], REWARDS[i].itemQuantity[j], "Item quantity mismatch");
+ }
+ }
+
+ // Test getting non-existent reward (should revert)
+ vm.expectRevert();
+ allOrNothing.getReward(keccak256("NonExistentReward"));
+ }
+
+ /**
+ * @notice Tests the getRaisedAmount functionality
+ * @dev Verifies that the total raised amount is correctly tracked and returned.
+ * Tests progression from zero to multiple pledges to ensure accurate accumulation.
+ * Note that raised amount only tracks pledge amounts, not shipping fees.
+ */
+ function test_getRaisedAmount() external {
+ addRewards(
+ users.creator1Address,
+ address(allOrNothing),
+ REWARD_NAMES,
+ REWARDS
+ );
+
+ // Initially should be zero
+ uint256 initialRaised = allOrNothing.getRaisedAmount();
+ assertEq(initialRaised, 0, "Initial raised amount should be zero");
+
+ // Make a pledge and check raised amount
+ pledgeForAReward(
+ users.backer1Address,
+ LAUNCH_TIME,
+ address(allOrNothing),
+ PLEDGE_AMOUNT,
+ SHIPPING_FEE,
+ REWARD_NAME_1_HASH
+ );
+
+ uint256 raisedAfterFirstPledge = allOrNothing.getRaisedAmount();
+ assertEq(raisedAfterFirstPledge, PLEDGE_AMOUNT, "Raised amount should equal first pledge amount");
+
+ // Make another pledge and check raised amount
+ pledgeWithoutAReward(
+ users.backer2Address,
+ LAUNCH_TIME,
+ address(allOrNothing),
+ GOAL_AMOUNT
+ );
+
+ uint256 finalRaised = allOrNothing.getRaisedAmount();
+ assertEq(finalRaised, PLEDGE_AMOUNT + GOAL_AMOUNT, "Raised amount should equal sum of all pledges");
+ }
+
+ /**
+ * @notice Tests the pauseTreasury functionality
+ * @dev Verifies that the treasury can be paused by platform admin and that the paused
+ * state is correctly set. Validates that the Paused event is emitted from the
+ * correct contract when the pause operation is executed.
+ */
+ function test_pauseTreasury() external {
+ bytes32 pauseReason = keccak256("Test pause");
+
+ assertFalse(allOrNothing.paused(), "Treasury should not be paused initially");
+
+ Vm.Log[] memory logs = pauseTreasury(
+ users.platform1AdminAddress,
+ address(allOrNothing),
+ pauseReason
+ );
+
+ assertTrue(allOrNothing.paused(), "Treasury should be paused");
+
+ // Use LogDecoder to find and verify the Paused event
+ Vm.Log memory pausedLog = findLogByTopic(
+ logs,
+ keccak256("Paused(address,bytes32)")
+ );
+
+ assertEq(pausedLog.emitter, address(allOrNothing), "Event should be emitted by allOrNothing contract");
+ }
+
+ /**
+ * @notice Tests the unpauseTreasury functionality
+ * @dev Verifies that the treasury can be unpaused by platform admin after being paused.
+ * Ensures proper state transition from paused to unpaused and validates that the
+ * Unpaused event is correctly emitted from the treasury contract.
+ */
+ function test_unpauseTreasury() external {
+ bytes32 pauseReason = keccak256("Test pause");
+ bytes32 unpauseReason = keccak256("Test unpause");
+
+ pauseTreasury(users.platform1AdminAddress, address(allOrNothing), pauseReason);
+ assertTrue(allOrNothing.paused(), "Treasury should be paused");
+
+ Vm.Log[] memory logs = unpauseTreasury(
+ users.platform1AdminAddress,
+ address(allOrNothing),
+ unpauseReason
+ );
+
+ assertFalse(allOrNothing.paused(), "Treasury should not be paused");
+
+ // Use LogDecoder to find and verify the Unpaused event
+ Vm.Log memory unpausedLog = findLogByTopic(
+ logs,
+ keccak256("Unpaused(address,bytes32)")
+ );
+
+ assertEq(unpausedLog.emitter, address(allOrNothing), "Event should be emitted by allOrNothing contract");
+ }
+
+ /**
+ * @notice Tests the cancelTreasury functionality by platform admin
+ * @dev Verifies that the treasury can be cancelled by platform admin and that the cancelled
+ * state is permanently set. Validates that the Cancelled event is emitted correctly
+ * and that cancellation is an irreversible operation.
+ */
+ function test_cancelTreasury() external {
+ bytes32 cancelReason = keccak256("Test cancellation");
+
+ assertFalse(allOrNothing.cancelled(), "Treasury should not be cancelled initially");
+
+ Vm.Log[] memory logs = cancelTreasury(
+ users.platform1AdminAddress,
+ address(allOrNothing),
+ cancelReason
+ );
+
+ assertTrue(allOrNothing.cancelled(), "Treasury should be cancelled");
+
+ // Use LogDecoder to find and verify the Cancelled event
+ Vm.Log memory cancelledLog = findLogByTopic(
+ logs,
+ keccak256("Cancelled(address,bytes32)")
+ );
+
+ assertEq(cancelledLog.emitter, address(allOrNothing), "Event should be emitted by allOrNothing contract");
+ }
+
+ /**
+ * @notice Tests cancelTreasury functionality by campaign owner
+ * @dev Verifies that the campaign owner can also cancel the treasury, demonstrating
+ * the dual authorization model where both platform admin and campaign owner
+ * have cancellation privileges. Validates proper event emission and state change.
+ */
+ function test_cancelTreasuryByCampaignOwner() external {
+ bytes32 cancelReason = keccak256("Owner cancellation");
+
+ assertFalse(allOrNothing.cancelled(), "Treasury should not be cancelled initially");
+
+ // Cancel the treasury as campaign owner using helper function
+ Vm.Log[] memory logs = cancelTreasury(
+ users.creator1Address,
+ address(allOrNothing),
+ cancelReason
+ );
+
+ // Verify treasury is cancelled
+ assertTrue(allOrNothing.cancelled(), "Treasury should be cancelled by owner");
+
+ // Use LogDecoder to find and verify the Cancelled event
+ Vm.Log memory cancelledLog = findLogByTopic(
+ logs,
+ keccak256("Cancelled(address,bytes32)")
+ );
+
+ assertEq(cancelledLog.emitter, address(allOrNothing), "Event should be emitted by allOrNothing contract");
+ }
+
+ /**
+ * @notice Tests the name functionality
+ * @dev Verifies that the contract name is correctly returned and matches the value
+ * that was set during contract initialization. Tests the ERC721 metadata extension.
+ */
+ function test_name() external {
+ string memory contractName = allOrNothing.name();
+ assertEq(contractName, NAME, "Contract name should match initialized name");
+ }
+
+ /**
+ * @notice Tests the symbol functionality
+ * @dev Verifies that the contract symbol is correctly returned and matches the value
+ * that was set during contract initialization. Tests the ERC721 metadata extension.
+ */
+ function test_symbol() external {
+ string memory contractSymbol = allOrNothing.symbol();
+ assertEq(contractSymbol, SYMBOL, "Contract symbol should match initialized symbol");
+ }
+
+ /**
+ * @notice Tests the getPlatformHash functionality
+ * @dev Verifies that the platform hash is correctly returned and matches the value
+ * that was set during contract initialization. This hash identifies which platform
+ * the treasury belongs to.
+ */
+ function test_getPlatformHash() external {
+ bytes32 platformHash = allOrNothing.getPlatformHash();
+ assertEq(platformHash, PLATFORM_1_HASH, "Platform hash should match initialized value");
+ }
+
+ /**
+ * @notice Tests the getPlatformFeePercent functionality
+ * @dev Verifies that the platform fee percentage is correctly returned and matches
+ * the value that was set during contract initialization. This percentage determines
+ * the platform's share of successful campaign funds.
+ */
+ function test_getPlatformFeePercent() external {
+ uint256 platformFeePercent = allOrNothing.getPlatformFeePercent();
+ assertEq(platformFeePercent, PLATFORM_FEE_PERCENT, "Platform fee percent should match initialized value");
+ }
+
+ /**
+ * @notice Tests the pledgeForAReward functionality
+ * @dev Verifies that users can pledge for specific rewards, including proper token transfers,
+ * NFT minting, and balance updates. Confirms that the backer receives an NFT representing
+ * their pledge and that funds (pledge amount + shipping fee) are correctly transferred
+ * to the treasury. Tests the complete reward-based pledging workflow.
+ */
function test_pledgeForAReward() external {
addRewards(
users.creator1Address,
@@ -63,24 +359,98 @@ contract AllOrNothingFunction_Integration_Shared_Test is
bytes32[] memory rewards
) = pledgeForAReward(
users.backer1Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
PLEDGE_AMOUNT,
SHIPPING_FEE,
- LAUNCH_TIME,
REWARD_NAME_1_HASH
);
- uint256 backerBalance = testUSD.balanceOf(users.backer1Address);
- uint256 treasuryBalance = testUSD.balanceOf(address(allOrNothing));
+ uint256 treasuryBalance = testToken.balanceOf(address(allOrNothing));
uint256 backerNftBalance = allOrNothing.balanceOf(users.backer1Address);
- address nftOwnerAddress = allOrNothing.ownerOf(pledgeForARewardTokenId);
+ address nftOwnerAddress = allOrNothing.ownerOf(tokenId);
+
+ // Verify Receipt event was emitted with correct data
+ Vm.Log memory receiptLog = findLogByTopic(
+ logs,
+ keccak256("Receipt(address,bytes32,uint256,uint256,uint256,bytes32[])")
+ );
+ assertEq(receiptLog.emitter, address(allOrNothing), "Receipt event should be emitted by allOrNothing contract");
+
+ // Verify state changes
+ assertEq(users.backer1Address, nftOwnerAddress, "Backer should own the NFT");
+ assertEq(PLEDGE_AMOUNT + SHIPPING_FEE, treasuryBalance, "Treasury should contain pledge amount + shipping fee");
+ assertEq(1, backerNftBalance, "Backer should have exactly 1 NFT");
+ assertEq(rewards[0], REWARD_NAME_1_HASH, "Reward name should match");
+ }
+
+ /**
+ * @notice Tests the pledgeWithoutAReward functionality
+ * @dev Verifies that users can make pledges without selecting rewards, including proper
+ * token transfers, NFT minting, and balance updates. Confirms that the backer receives
+ * an NFT representing their pledge and that only the pledge amount is transferred
+ * (no shipping fees since no rewards are selected). Tests the basic pledging workflow.
+ */
+ function test_pledgeWithoutAReward() external {
+ // Get initial balances
+ uint256 initialBackerBalance = testToken.balanceOf(users.backer1Address);
+ uint256 initialTreasuryBalance = testToken.balanceOf(address(allOrNothing));
+ uint256 initialBackerNftBalance = allOrNothing.balanceOf(users.backer1Address);
+
+ // Make a pledge without reward
+ (, uint256 tokenId) = pledgeWithoutAReward(
+ users.backer1Address,
+ LAUNCH_TIME,
+ address(allOrNothing),
+ PLEDGE_AMOUNT
+ );
+
+ // Get final balances
+ uint256 finalBackerBalance = testToken.balanceOf(users.backer1Address);
+ uint256 finalTreasuryBalance = testToken.balanceOf(address(allOrNothing));
+ uint256 finalBackerNftBalance = allOrNothing.balanceOf(users.backer1Address);
+ address nftOwnerAddress = allOrNothing.ownerOf(tokenId);
+
+ // Verify token transfers
+ assertEq(
+ initialBackerBalance - finalBackerBalance,
+ PLEDGE_AMOUNT,
+ "Incorrect amount deducted from backer"
+ );
+ assertEq(
+ finalTreasuryBalance - initialTreasuryBalance,
+ PLEDGE_AMOUNT,
+ "Incorrect amount transferred to treasury"
+ );
+
+ // Verify NFT minting
+ assertEq(
+ finalBackerNftBalance - initialBackerNftBalance,
+ 1,
+ "Backer should receive exactly one NFT"
+ );
+ assertEq(
+ nftOwnerAddress,
+ users.backer1Address,
+ "Backer should own the minted NFT"
+ );
- assertEq(users.backer1Address, nftOwnerAddress);
- assertEq(PLEDGE_AMOUNT + SHIPPING_FEE, treasuryBalance);
- assertEq(1, backerNftBalance);
+ // Verify treasury balance matches expected amount (no shipping fees)
+ assertEq(
+ finalTreasuryBalance,
+ PLEDGE_AMOUNT,
+ "Treasury should only contain the pledge amount"
+ );
}
+ /**
+ * @notice Tests the claimRefund functionality for both reward and non-reward pledges
+ * @dev Verifies that backers can claim refunds when campaigns fail to meet their goals.
+ * Tests both reward pledges (with shipping fees) and non-reward pledges, ensuring
+ * proper refund amounts and that the correct addresses receive refunds for both types.
+ * Validates that refunds include shipping fees for reward pledges and that NFTs are
+ * burned upon successful refund claims.
+ */
function test_claimRefund() external {
addRewards(
users.creator1Address,
@@ -89,36 +459,68 @@ contract AllOrNothingFunction_Integration_Shared_Test is
REWARDS
);
+ // Create a pledge with reward
(, uint256 rewardTokenId, ) = pledgeForAReward(
users.backer1Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
PLEDGE_AMOUNT,
SHIPPING_FEE,
- LAUNCH_TIME,
REWARD_NAME_1_HASH
);
- (, uint256 tokenId) = pledgeWithoutAReward(
+ // Create a pledge without reward
+ (, uint256 nonRewardTokenId) = pledgeWithoutAReward(
users.backer1Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
- PLEDGE_AMOUNT,
- LAUNCH_TIME
+ PLEDGE_AMOUNT
);
+ // Test refund for pledge without reward
+ (
+ ,
+ uint256 refundedNonRewardTokenId,
+ uint256 nonRewardRefundAmount,
+ address nonRewardClaimer
+ ) = claimRefund(
+ users.backer1Address,
+ LAUNCH_TIME + 1,
+ address(allOrNothing),
+ nonRewardTokenId
+ );
+
+ // Verify non-reward refund
+ assertEq(refundedNonRewardTokenId, nonRewardTokenId, "Incorrect non-reward token ID refunded");
+ assertEq(nonRewardRefundAmount, PLEDGE_AMOUNT, "Incorrect non-reward refund amount");
+ assertEq(nonRewardClaimer, users.backer1Address, "Incorrect non-reward claimer address");
+
+ // Test refund for pledge with reward
(
- Vm.Log[] memory refundLogs,
- uint256 refundedTokenId,
- uint256 refundAmount,
- address claimer
- ) = claimRefund(users.backer1Address, address(allOrNothing), tokenId);
+ ,
+ uint256 refundedRewardTokenId,
+ uint256 rewardRefundAmount,
+ address rewardClaimer
+ ) = claimRefund(
+ users.backer1Address,
+ LAUNCH_TIME + 1,
+ address(allOrNothing),
+ rewardTokenId
+ );
- assertEq(refundedTokenId, tokenId);
- assertEq(refundAmount, PLEDGE_AMOUNT);
- assertEq(claimer, users.backer1Address);
+ // Verify reward refund (should include pledge amount + shipping fee)
+ assertEq(refundedRewardTokenId, rewardTokenId, "Incorrect reward token ID refunded");
+ assertEq(rewardRefundAmount, PLEDGE_AMOUNT + SHIPPING_FEE, "Incorrect reward refund amount");
+ assertEq(rewardClaimer, users.backer1Address, "Incorrect reward claimer address");
}
+ /**
+ * @notice Tests the disburseFees functionality
+ * @dev Verifies that protocol and platform fees are correctly calculated and distributed
+ * when a campaign succeeds. Tests the fee calculation logic and ensures proper
+ * allocation between protocol and platform shares. Only executes after campaign
+ * deadline and when success conditions are met.
+ */
function test_disburseFees() external {
addRewards(
users.creator1Address,
@@ -129,19 +531,17 @@ contract AllOrNothingFunction_Integration_Shared_Test is
pledgeForAReward(
users.backer1Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
PLEDGE_AMOUNT,
SHIPPING_FEE,
- LAUNCH_TIME,
REWARD_NAME_1_HASH
);
pledgeWithoutAReward(
users.backer2Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
- GOAL_AMOUNT,
- LAUNCH_TIME
+ GOAL_AMOUNT
);
uint256 totalPledged = GOAL_AMOUNT + PLEDGE_AMOUNT;
@@ -150,13 +550,20 @@ contract AllOrNothingFunction_Integration_Shared_Test is
Vm.Log[] memory logs,
uint256 protocolShare,
uint256 platformShare
- ) = disburseFees(address(allOrNothing), DEADLINE);
+ ) = disburseFees(address(allOrNothing), DEADLINE + 1);
uint256 expectedProtocolShare = (totalPledged * PROTOCOL_FEE_PERCENT) /
PERCENT_DIVIDER;
uint256 expectedPlatformShare = (totalPledged * PLATFORM_FEE_PERCENT) /
PERCENT_DIVIDER;
+ // Verify FeesDisbursed event was emitted
+ Vm.Log memory feesLog = findLogByTopic(
+ logs,
+ keccak256("FeesDisbursed(uint256,uint256)")
+ );
+ assertEq(feesLog.emitter, address(allOrNothing), "FeesDisbursed event should be emitted by allOrNothing contract");
+
assertEq(
protocolShare,
expectedProtocolShare,
@@ -169,6 +576,13 @@ contract AllOrNothingFunction_Integration_Shared_Test is
);
}
+ /**
+ * @notice Tests the withdraw functionality
+ * @dev Verifies that campaign creators can withdraw remaining funds after successful
+ * campaigns and fee disbursement. Tests proper calculation of withdrawal amounts
+ * after deducting protocol and platform fees, and confirms funds go to the correct
+ * recipient (campaign owner). Includes shipping fees in the final withdrawal amount.
+ */
function test_withdraw() external {
addRewards(
users.creator1Address,
@@ -179,23 +593,21 @@ contract AllOrNothingFunction_Integration_Shared_Test is
pledgeForAReward(
users.backer1Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
PLEDGE_AMOUNT,
SHIPPING_FEE,
- LAUNCH_TIME,
REWARD_NAME_1_HASH
);
pledgeWithoutAReward(
users.backer2Address,
- address(testUSD),
+ LAUNCH_TIME,
address(allOrNothing),
- GOAL_AMOUNT,
- LAUNCH_TIME
+ GOAL_AMOUNT
);
uint256 totalPledged = GOAL_AMOUNT + PLEDGE_AMOUNT;
- disburseFees(address(allOrNothing), DEADLINE);
+ disburseFees(address(allOrNothing), DEADLINE + 1);
(Vm.Log[] memory logs, address to, uint256 amount) = withdraw(
address(allOrNothing),
@@ -211,6 +623,13 @@ contract AllOrNothingFunction_Integration_Shared_Test is
protocolShare -
platformShare;
+ // Verify WithdrawalSuccessful event was emitted
+ Vm.Log memory withdrawalLog = findLogByTopic(
+ logs,
+ keccak256("WithdrawalSuccessful(address,uint256)")
+ );
+ assertEq(withdrawalLog.emitter, address(allOrNothing), "WithdrawalSuccessful event should be emitted by allOrNothing contract");
+
assertEq(
to,
users.creator1Address,
@@ -218,4 +637,4 @@ contract AllOrNothingFunction_Integration_Shared_Test is
);
assertEq(amount, expectedAmount, "Incorrect withdrawal amount");
}
-}
+}
\ No newline at end of file
diff --git a/test/foundry/unit/CampaignInfoFactory.t.sol b/test/foundry/unit/CampaignInfoFactory.t.sol
index 32a6d313..803a83bb 100644
--- a/test/foundry/unit/CampaignInfoFactory.t.sol
+++ b/test/foundry/unit/CampaignInfoFactory.t.sol
@@ -1,11 +1,11 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import {CampaignInfoFactory} from "src/CampaignInfoFactory.sol";
import {GlobalParams} from "src/GlobalParams.sol";
import {TreasuryFactory} from "src/TreasuryFactory.sol";
-import {TestUSD} from "src/TestUSD.sol";
+import {TestToken} from "../../mocks/TestToken.sol";
import {Defaults} from "../Base.t.sol";
import {ICampaignData} from "src/interfaces/ICampaignData.sol";
import {CampaignInfo} from "src/CampaignInfo.sol";
@@ -14,22 +14,24 @@ contract CampaignInfoFactory_UnitTest is Test, Defaults {
CampaignInfoFactory internal factory;
TreasuryFactory internal treasuryFactory;
GlobalParams internal globalParams;
- TestUSD internal testUSD;
+ TestToken internal testToken;
CampaignInfo internal campaignInfoImplementation;
address internal admin = address(0xA11CE);
function setUp() public {
-
- testUSD = new TestUSD();
+ testToken = new TestToken(tokenName, tokenSymbol);
globalParams = new GlobalParams(
admin,
- address(testUSD),
+ address(testToken),
PROTOCOL_FEE_PERCENT
);
campaignInfoImplementation = new CampaignInfo(address(this));
treasuryFactory = new TreasuryFactory(globalParams);
- factory = new CampaignInfoFactory(globalParams, address(campaignInfoImplementation));
+ factory = new CampaignInfoFactory(
+ globalParams,
+ address(campaignInfoImplementation)
+ );
vm.startPrank(admin);
globalParams.enlistPlatform(
PLATFORM_1_HASH,
@@ -47,7 +49,6 @@ contract CampaignInfoFactory_UnitTest is Test, Defaults {
// vm.stopPrank();
}
-
function testCreateCampaignDeploysSuccessfully() public {
factory._initialize(address(treasuryFactory), address(globalParams));
diff --git a/test/foundry/unit/GlobalParams.t.sol b/test/foundry/unit/GlobalParams.t.sol
index ca4f0608..05c82ffa 100644
--- a/test/foundry/unit/GlobalParams.t.sol
+++ b/test/foundry/unit/GlobalParams.t.sol
@@ -1,19 +1,20 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import {GlobalParams} from "src/GlobalParams.sol";
-import {TestUSD} from "src/TestUSD.sol";
+import {Defaults} from "../Base.t.sol";
+import {TestToken} from "../../mocks/TestToken.sol";
-contract GlobalParams_UnitTest is Test {
+contract GlobalParams_UnitTest is Test, Defaults{
GlobalParams internal globalParams;
- TestUSD internal token;
+ TestToken internal token;
address internal admin = address(0xA11CE);
uint256 internal protocolFee = 300; // 3%
function setUp() public {
- token = new TestUSD();
+ token = new TestToken(tokenName, tokenSymbol);
globalParams = new GlobalParams(admin, address(token), protocolFee);
}
@@ -50,4 +51,4 @@ contract GlobalParams_UnitTest is Test {
vm.expectRevert();
globalParams.updateTokenAddress(address(0xBEEF));
}
-}
\ No newline at end of file
+}
diff --git a/test/foundry/unit/TestUSD.t.sol b/test/foundry/unit/TestToken.t.sol
similarity index 69%
rename from test/foundry/unit/TestUSD.t.sol
rename to test/foundry/unit/TestToken.t.sol
index cd1a2480..0ba3c4ed 100644
--- a/test/foundry/unit/TestUSD.t.sol
+++ b/test/foundry/unit/TestToken.t.sol
@@ -1,17 +1,18 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
-import {TestUSD} from "src/TestUSD.sol";
+import {TestToken} from "../../mocks/TestToken.sol";
+import {Defaults} from "../Base.t.sol";
-contract TestUSD_UnitTest is Test {
- TestUSD internal token;
+contract TestToken_UnitTest is Test, Defaults {
+ TestToken internal token;
address internal user = address(0x1234);
uint256 internal mintAmount = 1_000 * 1e18;
function setUp() public {
- token = new TestUSD();
+ token = new TestToken(tokenName, tokenSymbol);
}
function testMintIncreasesBalance() public {
@@ -26,4 +27,4 @@ contract TestUSD_UnitTest is Test {
token.transfer(recipient, 200 * 1e18);
assertEq(token.balanceOf(recipient), 200 * 1e18);
}
-}
\ No newline at end of file
+}
diff --git a/test/foundry/unit/TreasuryFactory.t.sol b/test/foundry/unit/TreasuryFactory.t.sol
index 41187800..3a7a6785 100644
--- a/test/foundry/unit/TreasuryFactory.t.sol
+++ b/test/foundry/unit/TreasuryFactory.t.sol
@@ -1,16 +1,17 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import {TreasuryFactory} from "src/TreasuryFactory.sol";
import {GlobalParams} from "src/GlobalParams.sol";
-import {TestUSD} from "src/TestUSD.sol";
+import {TestToken} from "../../mocks/TestToken.sol";
+import {Defaults} from "../Base.t.sol";
import {AdminAccessChecker} from "src/utils/AdminAccessChecker.sol";
-contract TreasuryFactory_UpdatedUnitTest is Test {
+contract TreasuryFactory_UpdatedUnitTest is Test, Defaults {
TreasuryFactory internal factory;
GlobalParams internal globalParams;
- TestUSD internal testUSD;
+ TestToken internal testToken;
address internal protocolAdmin = address(0xA11CE);
address internal platformAdmin = address(0xBEEF);
@@ -23,8 +24,8 @@ contract TreasuryFactory_UpdatedUnitTest is Test {
uint256 internal platformFee = 300; // 3%
function setUp() public {
- testUSD = new TestUSD();
- globalParams = new GlobalParams(protocolAdmin, address(testUSD), 300);
+ testToken = new TestToken(tokenName, tokenSymbol);
+ globalParams = new GlobalParams(protocolAdmin, address(testToken), 300);
factory = new TreasuryFactory(globalParams);
// Label addresses for clarity
diff --git a/test/foundry/utils/Constants.sol b/test/foundry/utils/Constants.sol
index bf7e111e..f25eb6f0 100644
--- a/test/foundry/utils/Constants.sol
+++ b/test/foundry/utils/Constants.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
abstract contract Constants {
diff --git a/test/foundry/utils/Defaults.sol b/test/foundry/utils/Defaults.sol
index 17815d82..c77b2ea5 100644
--- a/test/foundry/utils/Defaults.sol
+++ b/test/foundry/utils/Defaults.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Constants} from "./Constants.sol";
@@ -30,6 +30,10 @@ contract Defaults is Constants, ICampaignData, IReward {
uint256 public immutable LAUNCH_TIME;
uint256 public immutable DEADLINE;
+ //Token details
+ string tokenName = "TestToken";
+ string tokenSymbol = "TST";
+
//Variables
CampaignData public CAMPAIGN_DATA;
AllOrNothing.Reward public REWARD1;
diff --git a/test/foundry/utils/Types.sol b/test/foundry/utils/Types.sol
index df4b5ffc..1331e769 100644
--- a/test/foundry/utils/Types.sol
+++ b/test/foundry/utils/Types.sol
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
struct Users {
diff --git a/test/mocks/TestToken.sol b/test/mocks/TestToken.sol
new file mode 100644
index 00000000..19414ef1
--- /dev/null
+++ b/test/mocks/TestToken.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import {ERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
+import {Ownable} from "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+
+/**
+ * @title TestToken
+ * @notice A test token `tUSD` which is used in the tests.
+ */
+contract TestToken is ERC20, Ownable {
+ constructor(
+ string memory _name,
+ string memory _symbol
+ ) ERC20(_name, _symbol) Ownable(msg.sender) {}
+
+ /**
+ * @notice Mints testToken token.
+ * @param to The token receivers address.
+ * @param amount The amount of tokens to mint.
+ */
+ function mint(address to, uint256 amount) public onlyOwner {
+ _mint(to, amount);
+ }
+}