From c660e84ab6a29c19ab27c8ce89308d672e1ab24f Mon Sep 17 00:00:00 2001 From: Adam Boudj Date: Sun, 18 Feb 2024 18:29:40 +0400 Subject: [PATCH] Initial commit --- .env.example | 11 + .github/ISSUE_TEMPLATE/1_general_issue.yml | 26 +++ .github/ISSUE_TEMPLATE/2_bug_report.yml | 43 ++++ .github/ISSUE_TEMPLATE/3_feature_request.yml | 31 +++ .github/ISSUE_TEMPLATE/4_security_report.yml | 31 +++ .../ISSUE_TEMPLATE/5_document_improvement.yml | 33 +++ .../6_build_deployment_issue.yml | 33 +++ .../pull_request_template.md | 22 ++ .github/workflows/ci.yml | 50 +++++ .github/workflows/coverage.yml | 44 ++++ .gitignore | 44 ++++ .gitmodules | 0 .prettierignore | 17 ++ .prettierrc | 17 ++ .solhint.json | 35 ++++ .solhintignore | 3 + CHANGELOG.md | 42 ++++ CODE_OF_CONDUCT.md | 46 +++++ CONTRIBUTING.md | 92 +++++++++ GAS_OPTIMIZATION.md | 70 +++++++ LICENSE | 21 ++ README.md | 193 ++++++++++++++++++ SECURITY.md | 73 +++++++ audits/.gitkeep | 0 contracts/Foo.sol | 18 ++ contracts/Lock.sol | 46 +++++ foundry.toml | 53 +++++ hardhat.config.ts | 25 +++ package.json | 81 ++++++++ remappings.txt | 4 + scripts/foundry/Base.s.sol | 41 ++++ scripts/foundry/Deploy.s.sol | 17 ++ scripts/hardhat/deploy.ts | 27 +++ test/foundry/Foo.t.sol | 56 +++++ test/foundry/Lock.t.sol | 49 +++++ test/hardhat/Foo.ts | 19 ++ test/hardhat/Lock.ts | 127 ++++++++++++ tsconfig.json | 11 + 38 files changed, 1551 insertions(+) create mode 100644 .env.example create mode 100644 .github/ISSUE_TEMPLATE/1_general_issue.yml create mode 100644 .github/ISSUE_TEMPLATE/2_bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/3_feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/4_security_report.yml create mode 100644 .github/ISSUE_TEMPLATE/5_document_improvement.yml create mode 100644 .github/ISSUE_TEMPLATE/6_build_deployment_issue.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/coverage.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 .solhint.json create mode 100644 .solhintignore create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 GAS_OPTIMIZATION.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 audits/.gitkeep create mode 100644 contracts/Foo.sol create mode 100644 contracts/Lock.sol create mode 100644 foundry.toml create mode 100644 hardhat.config.ts create mode 100644 package.json create mode 100644 remappings.txt create mode 100644 scripts/foundry/Base.s.sol create mode 100644 scripts/foundry/Deploy.s.sol create mode 100644 scripts/hardhat/deploy.ts create mode 100644 test/foundry/Foo.t.sol create mode 100644 test/foundry/Lock.t.sol create mode 100644 test/hardhat/Foo.ts create mode 100644 test/hardhat/Lock.ts create mode 100644 tsconfig.json diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..98c10287 --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +export API_KEY_ALCHEMY="YOUR_API_KEY_ALCHEMY" +export API_KEY_ARBISCAN="YOUR_API_KEY_ARBISCAN" +export API_KEY_BSCSCAN="YOUR_API_KEY_BSCSCAN" +export API_KEY_ETHERSCAN="YOUR_API_KEY_ETHERSCAN" +export API_KEY_GNOSISSCAN="YOUR_API_KEY_GNOSISSCAN" +export API_KEY_INFURA="YOUR_API_KEY_INFURA" +export API_KEY_OPTIMISTIC_ETHERSCAN="YOUR_API_KEY_OPTIMISTIC_ETHERSCAN" +export API_KEY_POLYGONSCAN="YOUR_API_KEY_POLYGONSCAN" +export API_KEY_SNOWTRACE="YOUR_API_KEY_SNOWTRACE" +export MNEMONIC="YOUR_MNEMONIC" +export FOUNDRY_PROFILE="default" diff --git a/.github/ISSUE_TEMPLATE/1_general_issue.yml b/.github/ISSUE_TEMPLATE/1_general_issue.yml new file mode 100644 index 00000000..1e2fac68 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_general_issue.yml @@ -0,0 +1,26 @@ +name: ๐Ÿ’ก General Inquiry & Suggestions +description: Share general questions or suggestions that don't fit other categories +title: "[GENERAL] " +labels: ["question", "enhancement"] +body: + - type: markdown + attributes: + value: "Got a question or suggestion? We're all ears!" + - type: textarea + attributes: + label: Inquiry or Suggestion + description: What would you like to share with us? + placeholder: "I'm wondering about..." + validations: + required: false + - type: input + attributes: + label: Relevant Links or References + description: Optionally, add any relevant links or references. + placeholder: "e.g., https://github.com/example" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/2_bug_report.yml b/.github/ISSUE_TEMPLATE/2_bug_report.yml new file mode 100644 index 00000000..60851d85 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_bug_report.yml @@ -0,0 +1,43 @@ +name: ๐Ÿ› Bug Report & Test Failures +description: Report unexpected behaviors or failing tests +title: "[BUG] " +labels: ["bug", "help wanted"] +body: + - type: markdown + attributes: + value: "Please fill out this form with as much detail as possible to help us pinpoint the issue." + - type: input + attributes: + label: Summary + description: Provide a brief summary of the issue. + placeholder: "e.g., Function fails to return the correct value." + validations: + required: true + - type: textarea + attributes: + label: Steps to Reproduce + description: Describe the steps to reproduce the issue. + placeholder: | + 1. Deploy the contract... + 2. Call the function... + 3. The incorrect value is returned... + validations: + required: true + - type: textarea + attributes: + label: Expected vs. Actual Behavior + description: Detail the expected outcome versus what actually happened. + placeholder: "Expected to return X, but got Y instead." + validations: + required: true + - type: input + attributes: + label: Environment + description: Specify your development environment (e.g., compiler version, test framework). + placeholder: "Solidity v0.8.4, Hardhat v2.3.0" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/3_feature_request.yml b/.github/ISSUE_TEMPLATE/3_feature_request.yml new file mode 100644 index 00000000..8e3c6061 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_feature_request.yml @@ -0,0 +1,31 @@ +name: โœจ Feature Requests & Performance Improvements +description: Suggest a new feature or performance enhancement +title: "[FEATURE] " +labels: ["enhancement", "good first issue"] +body: + - type: markdown + attributes: + value: "Your suggestions inspire us to improve. Share your ideas below!" + - type: input + attributes: + label: Feature or Improvement Description + description: Describe the feature or improvement you're suggesting. + placeholder: "e.g., Optimize gas usage in function Z." + validations: + required: true + - type: textarea + attributes: + label: Benefits & Outcomes + description: Explain the benefits of your suggestion and the expected outcomes. + placeholder: "This improvement will reduce gas costs by 30%..." + - type: input + attributes: + label: Any References? + description: Provide links or references to similar features or standards. + placeholder: "EIP-1234, https://github.com/example" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/4_security_report.yml b/.github/ISSUE_TEMPLATE/4_security_report.yml new file mode 100644 index 00000000..4f8d7b66 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4_security_report.yml @@ -0,0 +1,31 @@ +name: ๐Ÿ”’ Security Pre-Screening +description: Pre-screening for security-related reports +title: "[SECURITY PRE-SCREEN] " +labels: ["security", "triage needed"] +body: + - type: markdown + attributes: + value: "Security is our top priority. If you've discovered a potential security issue that is **critical or high** in nature and could affect our deployed contracts, **please do not report it here.** Instead, email us directly at security@biconomy.io for a confidential review. For all other security-related inquiries that do not pose an immediate risk to our deployed contracts, please proceed." + - type: checkboxes + attributes: + label: Security Level Acknowledgement + options: + - label: "I understand this issue will be public. It is NOT critical or high risk and does not endanger deployed contracts." + required: true + - type: input + attributes: + label: Overview + description: Provide a summary of the non-critical security concern or question. + placeholder: "e.g., Questions about the audit process." + validations: + required: true + - type: textarea + attributes: + label: Additional Details + description: Offer more detail on your concern or question. + placeholder: "Provide any additional context..." + - type: input + attributes: + label: Suggestions for Mitigation + description: (Optional) Suggest ways to address the concern. + placeholder: "Potential mitigation steps include..." diff --git a/.github/ISSUE_TEMPLATE/5_document_improvement.yml b/.github/ISSUE_TEMPLATE/5_document_improvement.yml new file mode 100644 index 00000000..32534f97 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/5_document_improvement.yml @@ -0,0 +1,33 @@ +name: ๐Ÿ“š Documentation Improvement +description: Propose improvements or report issues with documentation +title: "[DOCS] " +labels: ["documentation"] +body: + - type: markdown + attributes: + value: "Help us enhance our documentation for everyone." + - type: input + attributes: + label: Documentation Page/Section + description: Which page or section are you referring to? + placeholder: "e.g., README.md, NatSpec guidelines." + validations: + required: true + - type: textarea + attributes: + label: Suggested Improvements + description: Detail the improvements or corrections needed. + placeholder: "The section on XYZ could clarify..." + validations: + required: true + - type: input + attributes: + label: Additional Comments + description: Any other comments or suggestions? + placeholder: "Consider adding examples for..." + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml b/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml new file mode 100644 index 00000000..e0c69a15 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml @@ -0,0 +1,33 @@ +name: ๐Ÿ›  Build & Deployment Issues +description: Report issues related to building or deploying smart contracts +title: "[BUILD/DEPLOY] " +labels: ["bug", "help wanted"] +body: + - type: markdown + attributes: + value: "Help us identify build or deployment problems to improve our processes." + - type: input + attributes: + label: Issue Summary + description: Briefly describe the issue encountered. + placeholder: "e.g., Failed to deploy contract due to..." + validations: + required: true + - type: textarea + attributes: + label: Error Logs & Messages + description: Provide any error logs or messages seen. + placeholder: "Error: Failed to..." + validations: + required: true + - type: input + attributes: + label: Environment & Tools + description: Mention the tools and environment where the issue occurred. + placeholder: "e.g., Truffle v5.3, Rinkeby testnet" + - type: checkboxes + attributes: + label: Code of Conduct + options: + - label: I agree to follow this project's Code of Conduct. + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 00000000..fca427ab --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,22 @@ +## Pull Request for Smart Contract Improvement + +**Describe your changes:** + + + +**Link any related issues:** + + + +**Testing:** + + + +**Note:** Please ensure all tests and lint checks pass before requesting a review. If there are any errors, fix them prior to submission. + +**Checklist:** + +- [ ] I have performed a self-review of my own code. +- [ ] I have added tests that prove my fix is effective or that my feature works. +- [ ] I have made corresponding changes to the documentation, if applicable. +- [ ] My changes generate no new warnings or errors. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..2d52cb69 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: Test workflow +on: push +jobs: + lint: + name: Lint sources + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install foundry dependencies + run: forge install + + - name: Lint sources + run: yarn lint:sol + + unit_test: + name: Unit tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Create a fake .secret file + run: echo "primary twist rack vendor diagram image used route theme frown either will" > .secret + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install foundry dependencies + run: forge install + + - name: Build Typechain and Foundry + run: yarn build + + - name: Run Forge and Hardhat Tests + run: yarn test diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..d5f509d8 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,44 @@ +name: Coverage +on: push +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "20.x" + + - name: Install lcov (for genhtml) + run: sudo apt-get update && sudo apt-get install -y lcov + + - name: Install JavaScript Dependencies + run: yarn install --frozen-lockfile + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install Foundry Dependencies + run: forge install + + - name: Generate Hardhat & Foundry Coverage Report + run: yarn coverage:report + + - name: Upload Foundry Coverage Report to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage/foundry/lcov.info + flags: foundry + + - name: Upload Hardhat Coverage Report to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage/lcov.info + flags: hardhat diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9691a6f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# directories +cache +coverage +node_modules +out +docs +storageLayout + +# files +*.env +*.log +.DS_Store +.pnp.* +lcov.info +package-lock.json +pnpm-lock.yaml +yarn.lock + +# broadcasts +!broadcast +broadcast/* +broadcast/*/31337/ + +node_modules +.env + +# Hardhat files +/cache +/artifacts +/docs + +# TypeChain files +/typechain +/typechain-types + +# solidity-coverage files +/coverage +/coverage.json + +node_modules +.env + +# Foundry cache +cache_forge/solidity-files-cache.json \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..3996d20b --- /dev/null +++ b/.prettierignore @@ -0,0 +1,17 @@ +# directories +broadcast +cache +coverage +node_modules +out + +# files +*.env +*.log +.DS_Store +.pnp.* +bun.lockb +lcov.info +package-lock.json +pnpm-lock.yaml +yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..a56c9710 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,17 @@ +{ + "overrides": [ + { + "files": "*.sol", + "options": { + "printWidth": 120, + "tabWidth": 2, + "proseWrap": "always", + "useTabs": false, + "singleQuote": false, + "trailingComma": "all", + "bracketSpacing": true, + "plugins": ["prettier-plugin-solidity"] + } + } + ] +} diff --git a/.solhint.json b/.solhint.json new file mode 100644 index 00000000..a41dc0f7 --- /dev/null +++ b/.solhint.json @@ -0,0 +1,35 @@ +{ + "extends": "solhint:recommended", + "rules": { + "compiler-version": ["error", "^0.8.24"], + "func-visibility": ["warn", { "ignoreConstructors": true }], + "reentrancy": "error", + "state-visibility": "error", + "quotes": ["error", "double"], + "const-name-snakecase": "error", + "contract-name-camelcase": "error", + "event-name-camelcase": "error", + "func-name-mixedcase": "error", + "func-param-name-mixedcase": "error", + "modifier-name-mixedcase": "error", + "private-vars-leading-underscore": ["warn", { "strict": true }], + "use-forbidden-name": "error", + "var-name-mixedcase": "error", + "imports-on-top": "error", + "ordering": "error", + "visibility-modifier-order": "error", + "code-complexity": ["error", 7], + "function-max-lines": ["error", 80], + "max-line-length": ["warn", 120], + "no-empty-blocks": "error", + "no-unused-vars": "error", + "payable-fallback": "off", + "constructor-syntax": "error", + "explicit-types": "error", + "no-unused-import": "error", + "one-contract-per-file": "warn", + "reason-string": "error", + "custom-errors": "off" + }, + "plugins": ["prettier"] +} diff --git a/.solhintignore b/.solhintignore new file mode 100644 index 00000000..5e009ca8 --- /dev/null +++ b/.solhintignore @@ -0,0 +1,3 @@ +node_modules +artifacts +test \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..ab54d1a7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,42 @@ +# Changelog + +All notable changes to the `sc-template` project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +- Initial setup and configurations for both Foundry and Hardhat environments. +- Integration of GitHub Actions for CI/CD pipelines. +- Addition of linter configurations for Solidity and TypeScript. + +## [1.0.0] - 2024-01-01 + +### Added + +- `Foo.sol` and `Lock.sol` smart contracts under the `contracts` directory. +- Foundry and Hardhat configurations for building and testing smart contracts. +- Comprehensive testing scripts for Foundry and Hardhat environments in `test/foundry` and `test/hardhat`. +- GitHub Actions workflows for automated testing, linting, and security checks. +- Documentation for getting started, usage, and contribution guidelines. + +### Changed + +- Updated the README.md to provide detailed information about the project, installation instructions, and contribution guidelines. + +### Fixed + +- Minor bug fixes and performance improvements in smart contract code. +- Addressed linting issues in smart contracts and test scripts. + +### Security + +- Implemented security best practices in smart contract development. +- Established a security policy for reporting vulnerabilities. + +## [0.1.0] - 2023-XX-XX (Initial Pre-Release) + +### Added + +- Initial commit with basic project structure. +- Setup of development environments for Solidity smart contract development using Foundry and Hardhat. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..c5529118 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail 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 by contacting the project team at graeme.barnes@biconomy.io or adam.boudjemaa@biconomy.io. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other project leadership members. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f6aba0a8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,92 @@ +# Contributing to sc-template + +First off, thanks for taking the time to contribute to the `sc-template`! โค๏ธ Your efforts help build a strong, collaborative environment for developing robust smart contracts. + +## Table of Contents + +- [Contributing to sc-template](#contributing-to-sc-template) + - [Table of Contents](#table-of-contents) + - [I Have a Question](#i-have-a-question) + - [I Want To Contribute](#i-want-to-contribute) + - [Legal Notice](#legal-notice) + - [Reporting Bugs](#reporting-bugs) + - [Suggesting Enhancements](#suggesting-enhancements) + - [Your First Code Contribution](#your-first-code-contribution) + - [Improving The Documentation](#improving-the-documentation) + - [Styleguides](#styleguides) + - [Commit Messages](#commit-messages) + - [Join The Project Team](#join-the-project-team) + - [**Recognition and Rewards**](#recognition-and-rewards) + - [Attribution](#attribution) + +## I Have a Question + +If you have a question, please make sure to go through our [Documentation](https://docs.biconomy.io/) first. Many common questions are already answered there. + +For questions that remain unanswered, feel free to ask by: + +- Opening an [Issue](https://github.com/bcnmy/sc-template/issues/new) with a detailed description of your query. +- Joining our community discussions on [Discord](https://discord.gg/biconomy) or [Telegram](https://t.me/biconomy). + +## I Want To Contribute + +### Legal Notice + +When contributing to this project, you agree that you have authored 100% of the content, have the necessary rights to the content, and that the content you contribute can be provided under the project license. + +### Reporting Bugs + +A detailed bug report plays a crucial role in improving the `sc-template`. Before submitting a bug report: + +- Ensure you're using the latest version. +- Verify if it's a real bug and not an error on your side by consulting the [documentation](https://docs.biconomy.io/). +- Search both open and closed [issues](https://github.com/bcnmy/sc-template/issues?q=label%3Abug) to avoid duplicates. + +To submit a bug report, open an [issue](https://github.com/bcnmy/sc-template/issues/new) and include as much relevant information as possible. + +### Suggesting Enhancements + +We welcome suggestions for enhancements, including new features or improvements to existing ones. Before submitting: + +- Ensure you're using the latest version. +- Check the [documentation](https://docs.biconomy.io/) to see if the enhancement is already implemented. +- Search existing [issues](https://github.com/bcnmy/sc-template/issues) to avoid duplicates. + +To suggest an enhancement, open an [issue](https://github.com/bcnmy/sc-template/issues/new) with a clear title and detailed description. + +### Your First Code Contribution + +Ready to contribute code? Great! Here are some steps to get you started: + +1. Fork the repository and create your branch from `main`. +2. Write clear, concise, and functional code that adheres to our styleguides. +3. Ensure your changes are thoroughly tested, especially for critical paths. +4. Submit a pull request with a detailed description of your changes. + +### Improving The Documentation + +Good documentation is crucial for any project. To contribute: + +1. Identify gaps or inaccuracies in our existing documentation. +2. Propose changes that make the documentation clearer and more comprehensive. +3. Submit a pull request with your proposed changes. + +## Styleguides + +Our styleguides ensure consistency and quality across the codebase and documentation. Please review the [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html) and [JavaScript Style Guide](https://standardjs.com/rules.html) before contributing. + +## Commit Messages + +Use clear, concise commit messages that describe the changes you've made. Follow these [commit message conventions](https://www.conventionalcommits.org/en/v1.0.0/). + +## Join The Project Team + +Interested in becoming a more integral part of the `sc-template` team? Great! Start by consistently contributing to the project, and don't hesitate to reach out to us on [Discord](https://discord.gg/biconomy) or [Telegram](https://t.me/biconomy) to express your interest. + +## **Recognition and Rewards** + +We deeply value each contribution to Biconomy, whether it's through optimizing our smart contracts, enhancing security, or other valuable improvements. Noteworthy contributions may qualify for bounties, as outlined in our [GAS_OPTIMIZATION.md](./GAS_OPTIMIZATION.md) and [SECURITY.md](./SECURITY.md), and contributors will be celebrated in our **Contributor Hall of Fame**. Contributions that fall outside direct optimization or security enhancements but are deemed valuable by our team may also be eligible for recognition and rewards. Let's work together to build a more secure and efficient ecosystem. + +## Attribution + +This contributing guide is inspired by the open-source community and aims to foster a welcoming and collaborative environment. We're excited to see your contributions โ€“ let's build something great together! diff --git a/GAS_OPTIMIZATION.md b/GAS_OPTIMIZATION.md new file mode 100644 index 00000000..7575f163 --- /dev/null +++ b/GAS_OPTIMIZATION.md @@ -0,0 +1,70 @@ +# **Biconomy Smart Contract Optimization Bounty Program** + +## **Introduction** + +Biconomy is dedicated to enhancing the efficiency and sustainability of our decentralized ecosystem. Through our **Smart Contract Optimization Bounty Program**, we invite global developers to contribute towards optimizing gas efficiency across our suite of smart contracts. This initiative is key to reducing operational costs, improving scalability, and elevating the user experience within the blockchain ecosystem. + +For details on reporting security vulnerabilities or contributing to our project in other ways, please see our [SECURITY.md](./SECURITY.md) and [CONTRIBUTING.md](./CONTRIBUTING.md) files. We value all contributions that enhance the Biconomy ecosystem, including but not limited to code optimizations and security improvements. + +## **Program Objective** + +Our goal is to maximize gas efficiency in our smart contracts while ensuring the code remains **readable, maintainable, and thoroughly documented**.We value contributions that find the perfect harmony between optimization and clarity, as both are critical for the enduring success of blockchain projects. + +## **Rewards Structure** + +Contributors to the Biconomy Smart Contract Optimization Bounty Program will be rewarded for their efforts with **BICO tokens (ERC20)**, based on the cumulative gas savings achieved across all contracts. Furthermore, in addition to the bounty rewards, successful contributors will gain a spot in our **Contributor Hall of Fame**, where names or GitHub handles are honored within our repository and documentation, showcasing the impactful contributions made to the Biconomy ecosystem. + +### **Reward Tiers** + +- **Tier 1 (up to 10% Cumulative Gas Savings):** Receive $150 in BICO tokens for optimizing up to 10%. +- **Tier 2 (11-25% Cumulative Gas Savings):** Earn $600 in BICO tokens for achieving 11-25% savings. +- **Tier 3 (26-40% Cumulative Gas Savings):** Secure $2,000 in BICO tokens for 26-40% cumulative savings. +- **Tier 4 (41-55% Cumulative Gas Savings):** Gain $4,000 in BICO tokens for optimizing 41-55%. +- **Tier 5 (over 55% Cumulative Gas Savings):** Be rewarded with $7,500 in BICO tokens for surpassing 55% savings. + +## **Submission Guidelines** + +### **Identifying Opportunities** + +- Explore our smart contracts for potential gas optimization areas. + +### **Implementing Changes** + +- **Fork the `develop` branch** of the Biconomy repository. This ensures your updates are built on the latest features and fixes, preventing overlap with existing main branch plans. +- Maintain code clarity and documentation through your optimizations. + +### **Testing and Validation** + +- Validate your optimizations with thorough testing, ensuring both gas efficiency improvement and preserved functionality. +- Attach detailed test results with your submission. + +### **Submitting Your Work** + +- Open a pull request (PR) from your forked **develop branch**, detailing your changes, the rationale behind each optimization, and its gas usage impact. +- Highlight the cumulative gas savings achieved across all functions and contracts. + +## **Evaluation Criteria** + +Submissions will be evaluated on: + +- **Efficiency Improvement:** The cumulative percentage of gas savings. +- **Code Quality:** Enhancements should bolster clarity, maintainability, and documentation. +- **Innovation:** Creative solutions to optimization challenges. +- **Impact:** The significant contribution to the project's efficiency and sustainability. + +## **Eligibility Criteria** + +- Originality is a must, with no infringement on third-party rights. +- Include comprehensive documentation of optimizations and their impacts. +- Demonstrated effectiveness of optimizations with accompanying tests. +- Adherence to smart contract development and security best practices is required. + +## **Terms and Conditions** + +- Rewards, payable in BICO tokens, will be based on their USD value at distribution. +- Biconomy reserves the right to alter the program's terms or discontinue at its discretion. +- Reward tiers will be determined by the Biconomy team based on the evaluation criteria. + +This program is a unique opportunity for developers to showcase their expertise, contribute to a more efficient ecosystem, and earn rewards for their innovative solutions. We eagerly anticipate your contributions and the enhancements your optimizations will bring to our smart contracts. + +**We look forward to your innovative contributions and collectively advancing the efficiency of decentralized applications!** diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..84dbcc86 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Biconomy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..3bf95a3e --- /dev/null +++ b/README.md @@ -0,0 +1,193 @@ +[![Biconomy](https://img.shields.io/badge/Made_with_%F0%9F%8D%8A_by-Biconomy-ff4e17?style=flat)](https://biconomy.io) [![License MIT](https://img.shields.io/badge/License-MIT-blue?&style=flat)](./LICENSE) [![Hardhat](https://img.shields.io/badge/Built%20with-Hardhat-FFDB1C.svg)](https://hardhat.org/) [![Foundry](https://img.shields.io/badge/Built%20with-Foundry-FFBD10.svg)](https://getfoundry.sh/) + +![Codecov Hardhat Coverage](https://img.shields.io/codecov/c/gh/bcnmy/sc-template?token=2BYDIFQ56W&flag=hardhat&label=Hardhat-coverage&logo=codecov) ![Codecov Foundry Coverage](https://img.shields.io/codecov/c/gh/bcnmy/sc-template?token=2BYDIFQ56W&flag=foundry&label=Foundry-coverage&logo=codecov) + +# Smart Contract Template Base ๐Ÿš€ + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bcnmy/sc-template) + +This repository serves as a comprehensive foundation for smart contract projects, streamlining the development process with a focus on best practices, security, and efficiency. + +## ๐Ÿ“š Table of Contents + +- [๐Ÿš€ Introduction](#smart-contract-template-base-) +- [๐ŸŒŸ Features](#features) +- [๐Ÿ Getting Started](#getting-started) +- [๐Ÿ”ง Essential Scripts](#๏ธ-essential-scripts) +- [๐Ÿ”’ Security Audits](#-security-audits) +- [๐Ÿ† Biconomy Champions League](#-biconomy-champions-league-) +- [๐Ÿ“– Documentation and Resources](#documentation-and-resources) +- [๐Ÿ“„ License](#license) +- [๐Ÿค Connect with Biconomy](#connect-with-biconomy-) + +## Features + +- **Smart Contract Template Base**: A robust foundation for future smart contract projects. +- **Hardhat & Foundry Support**: Equipped with both Hardhat and Foundry tools and an adapted folder structure for seamless development. +- **Best Practices**: Adheres to industry best practices in smart contract programming to ensure code quality and security. +- **Continuous Integration & Deployment**: Utilizes GitHub Actions for automated testing and deployment, ensuring code reliability. +- **Strict Linting**: Implements Solhint based on the Solidity style guide, enhancing code quality and consistency. +- **Comprehensive Testing**: Includes a wide range of tests (unit, fuzz, fork) for both Foundry and Hardhat environments. +- **Environment Configuration**: Comes with `.env.example` for easy setup of API keys and environmental variables. +- **Code Formatting**: Uses Prettier to maintain a consistent code style across the project. +- **Configurations for Foundry & Hardhat**: Provides essential settings and scripts for building, testing, and deployment, tailored for both development environments. + +## Getting Started + +To kickstart your smart contract development with this template, follow these steps: + +### Prerequisites + +- Node.js (v18.x or later) +- Yarn (or npm) +- Foundry (Refer to [Foundry installation instructions](https://getfoundry.sh/docs/installation)) + +### Installation + +1. **Clone the repository:** + +```bash +git clone https://github.com/bcnmy/sc-template.git +cd sc-template +``` + +2. **Install dependencies:** + +```bash +yarn install +``` + +3. **Setup environment variables:** + +Copy `.env.example` to `.env` and fill in your details. + +## ๐Ÿ› ๏ธ Essential Scripts + +Execute key operations for Foundry and Hardhat with these scripts. Append `:forge` or `:hardhat` to run them in the respective environment. + +### ๐Ÿ—๏ธ Build Contracts + +```bash +yarn build +``` + +Compiles contracts for both Foundry and Hardhat. + +### ๐Ÿงช Run Tests + +```bash +yarn test +``` + +Carries out tests to verify contract functionality. + +### โ›ฝ Gas Report + +```bash +yarn test:gas +``` + +Creates detailed reports for test coverage. + +### ๐Ÿ“Š Coverage Report + +```bash +yarn coverage +``` + +Creates detailed reports for test coverage. + +### ๐Ÿ“„ Documentation + +```bash +yarn docs +``` + +Generate documentation from NatSpec comments. + +### ๐Ÿš€ Deploy Contracts + +```bash +yarn deploy +``` + +Deploys contracts onto the blockchain network. + +### ๐ŸŽจ Lint Code + +```bash +yarn lint +``` + +Checks code for style and potential errors. + +### ๐Ÿ–Œ๏ธ Auto-fix Linting Issues + +```bash +yarn lint:fix +``` + +Automatically fixes linting problems found. + +### ๐Ÿš€ Generating Storage Layout + +```bash +yarn check +``` + +To generate reports of the storage layout for potential upgrades safety using `hardhat-storage-layout`. + +๐Ÿ”„ Add `:forge` or `:hardhat` to any script above to target only Foundry or Hardhat environment, respectively. + +## ๐Ÿ”’ Security Audits + +| Auditor | Date | Final Report Link | +| --------- | ---------- | ----------------------- | +| Firm Name | DD-MM-YYYY | [View Report](./audits) | +| Firm Name | DD-MM-YYYY | [View Report](./audits) | +| Firm Name | DD-MM-YYYY | [View Report](./audits) | + +## ๐Ÿ† Biconomy Champions League ๐Ÿ† + +Welcome to the Champions League, a place where your contributions to Biconomy are celebrated and immortalized in our Hall of Fame. This elite group showcases individuals who have significantly advanced our mission, from enhancing code efficiency to strengthening security, and enriching our documentation. + +### Champions Roster + +| ๐ŸŠ Contributor | ๐Ÿ›ก๏ธ Domain | +| -------------- | ----------------- | +| @user1 | Code Optimization | +| @user2 | Security | +| @user3 | Documentation | +| ... | ... | + +### Entering the League + +Your journey to becoming a champion can start in any domain: + +- **Code Wizards**: Dive into our [Gas Optimization](./GAS_OPTIMIZATION.md) efforts. +- **Security Guardians**: Enhance our safety following the [Security Guidelines](./SECURITY.md). +- **Documentation Scribes**: Elevate our knowledge base with your contributions. + +The **Champions League** is not just a recognition, it's a testament to the impactful work done by our community. Whether you're optimizing gas usage or securing our contracts, your contributions help shape the future of Biconomy. + +> **To Join**: Leave a lasting impact in your chosen area. Our Hall of Fame is regularly updated to honor our most dedicated contributors. + +Let's build a legacy together, championing innovation and excellence in the blockchain space. + +## Documentation and Resources + +For a comprehensive understanding of our project and to contribute effectively, please refer to the following resources: + +- [**Contributing Guidelines**](./CONTRIBUTING.md): Learn how to contribute to our project, from code contributions to documentation improvements. +- [**Code of Conduct**](./CODE_OF_CONDUCT.md): Our commitment to fostering an open and welcoming environment. +- [**Security Policy**](./SECURITY.md): Guidelines for reporting security vulnerabilities. +- [**Gas Optimization Program**](./GAS_OPTIMIZATION.md): Contribute towards optimizing gas efficiency of our smart contracts. +- [**Changelog**](./CHANGELOG.md): Stay updated with the changes and versions. + +## License + +This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details. + +## Connect with Biconomy ๐ŸŠ + +[![Website](https://img.shields.io/badge/๐ŸŠ-Website-ff4e17?style=for-the-badge&logoColor=white)](https://biconomy.io) [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/biconomy) [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/biconomy) [![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/biconomy) [![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/biconomy) [![YouTube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UC0CtA-Dw9yg-ENgav_VYjRw) [![GitHub](https://img.shields.io/badge/GitHub-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/bcnmy/) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..78baefe5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,73 @@ +# Security Policy + +## Reporting a Vulnerability + +The safety and security of our smart contract platform is our top priority. If you have discovered a security vulnerability, we appreciate your help in disclosing it to us responsibly. + +### Contact Us Directly for Critical or High-Risk Findings + +For critical or high-impact vulnerabilities that could affect our users, **please contact us directly** at: + +- Email: security@biconomy.io + +We'll work with you to assess and understand the scope of the issue. + +### For Other Issues + +For vulnerabilities that are less critical and do not immediately affect our users: + +1. Open an issue in our GitHub repository (`https://github.com/bcnmy/sc-template/issues`). + +2. Provide detailed information about the issue and steps to reproduce. + +If your findings are eligible for a bounty, we will follow up with you on the payment process. + +## Bug Bounty Program + +We run a bug bounty program to encourage and reward those who help us improve the security of our smart contracts. The rewards are distributed according to the impact of the vulnerability based on the severity levels outlined below. + +### Rewards by Threat Level + +- **Critical:** Up to $50,000 + +- **High:** Up to $10,000 + +- **Medium and Low:** Case by case + +In addition to security improvements, we actively support initiatives aimed at optimizing our smart contracts for better gas efficiency as outlined in our [GAS_OPTIMIZATION.md](./GAS_OPTIMIZATION.md). Contributors who make significant strides in either area will be recognized for their efforts. To learn more about making contributions across various areas, including potential rewards and our appreciation program, refer to our [CONTRIBUTING.md](./CONTRIBUTING.md). + +### Scope + +The bounty program covers code in the `main` branch of our repository, focusing on Solidity smart contracts. The vulnerability must not have already been addressed or fixed in the `develop` branch. + +### Eligibility + +To be eligible for a bounty, researchers must: + +- Report a security bug that has not been previously reported. + +- Not violate our testing policies (detailed below). + +- Follow responsible disclosure guidelines. + +### Testing Policies + +- Do not conduct testing on the mainnet or public testnets. Local forks should be used for testing. + +- Avoid testing that generates significant traffic or could lead to denial of service. + +- Do not disclose the vulnerability publicly until we have had the chance to address it. + +### Out of Scope + +- Known issues listed in the issue tracker or already fixed in the `develop` branch. + +- Issues in third-party components unless they directly affect our smart contracts. + +- Basic economic and governance attacks, e.g., 51% attacks. + +## Legal Notice + +By submitting a vulnerability report, you agree to comply with our responsible disclosure process. Public disclosure of the vulnerability without consent from us will render the vulnerability ineligible for a bounty. + +Thank you for helping to keep Biconomy ๐ŸŠ and the blockchain community safe! diff --git a/audits/.gitkeep b/audits/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/contracts/Foo.sol b/contracts/Foo.sol new file mode 100644 index 00000000..f419123f --- /dev/null +++ b/contracts/Foo.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.24; + +/** + * @title Foo + * @dev A simple contract demonstrating a pure function in Solidity. + */ +contract Foo { + /** + * @notice Returns the input value unchanged. + * @dev A pure function that does not alter or interact with contract state. + * @param value The uint256 value to be returned. + * @return uint256 The same value that was input. + */ + function id(uint256 value) external pure returns (uint256) { + return value; + } +} diff --git a/contracts/Lock.sol b/contracts/Lock.sol new file mode 100644 index 00000000..d11302f4 --- /dev/null +++ b/contracts/Lock.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +/** + * @title Lock + * @dev Implements a time-locked wallet that only allows withdrawals after a certain date. + */ +contract Lock { + uint256 public unlockTime; + address payable public owner; + + /** + * @dev Emitted when funds are withdrawn from the contract. + * @param amount The amount of Ether withdrawn. + * @param when The timestamp of the withdrawal. + */ + event Withdrawal(uint256 amount, uint256 when); + + /** + * @notice Creates a locked wallet. + * @param unlockTime_ The timestamp after which withdrawals can be made. + */ + constructor(uint256 unlockTime_) payable { + require(block.timestamp < unlockTime_, "Wrong Unlock time"); + + unlockTime = unlockTime_; + owner = payable(msg.sender); + } + + /** + * @notice Allows funds to be received via direct transfers. + */ + receive() external payable { } + + /** + * @notice Withdraws all funds if the unlock time has passed and the caller is the owner. + */ + function withdraw() public { + require(block.timestamp > unlockTime, "You can't withdraw yet"); + require(msg.sender == owner, "You aren't the owner"); + + emit Withdrawal(address(this).balance, block.timestamp); + + owner.transfer(address(this).balance); + } +} diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 00000000..06a162e1 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,53 @@ +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] + auto_detect_solc = false + block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT + bytecode_hash = "none" + evm_version = "paris" # See https://www.evmdiff.com/features?name=PUSH0&kind=opcode + fuzz = { runs = 1_000 } + gas_reports = ["*"] + optimizer = true + optimizer_runs = 1_000_000 + out = "out" + script = "scripts" + solc = "0.8.24" + src = "contracts" + test = "test" + cache_path = "cache_forge" + libs = ["node_modules", "lib"] + gas_reports_ignore = ["LockTest"] + +[profile.ci] + fuzz = { runs = 10_000 } + verbosity = 4 + +[etherscan] + arbitrum = { key = "${API_KEY_ARBISCAN}" } + avalanche = { key = "${API_KEY_SNOWTRACE}" } + goerli = { key = "${API_KEY_ETHERSCAN}" } + mainnet = { key = "${API_KEY_ETHERSCAN}" } + optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" } + polygon = { key = "${API_KEY_POLYGONSCAN}" } + sepolia = { key = "${API_KEY_ETHERSCAN}" } + +[fmt] + bracket_spacing = true + int_types = "long" + line_length = 120 + multiline_func_header = "all" + number_underscore = "thousands" + quote_style = "double" + tab_width = 4 + wrap_comments = true + +[rpc_endpoints] + arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}" + avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}" + goerli = "https://goerli.infura.io/v3/${API_KEY_INFURA}" + localhost = "http://localhost:8545" + mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" + optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}" + polygon = "https://polygon-mainnet.infura.io/v3/${API_KEY_INFURA}" + sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}" + diff --git a/hardhat.config.ts b/hardhat.config.ts new file mode 100644 index 00000000..a722fc61 --- /dev/null +++ b/hardhat.config.ts @@ -0,0 +1,25 @@ +import { HardhatUserConfig } from "hardhat/config"; +import "@nomicfoundation/hardhat-toolbox"; +import "hardhat-storage-layout"; +import "@bonadocs/docgen"; + +const config: HardhatUserConfig = { + solidity: { + version: "0.8.24", + settings: { + optimizer: { + enabled: true, + runs: 1000000, + details: { + yul: true, + }, + }, + }, + }, + docgen: { + projectName: "Biconomy", + projectDescription: "Sc-Template Description", + }, +}; + +export default config; diff --git a/package.json b/package.json new file mode 100644 index 00000000..528073a1 --- /dev/null +++ b/package.json @@ -0,0 +1,81 @@ +{ + "name": "", + "description": "", + "version": "1.0.0", + "author": { + "name": "Biconomy", + "url": "https://github.com/bcnmy" + }, + "dependencies": { + "@openzeppelin/contracts": "^5.0.1", + "hardhat": "^2.20.1" + }, + "devDependencies": { + "@bonadocs/docgen": "^1.0.1-alpha.1", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.5", + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.10", + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.4", + "@prb/test": "^0.6.4", + "@typechain/ethers-v6": "^0.5.1", + "@typechain/hardhat": "^9.1.0", + "@types/chai": "^4.3.11", + "@types/mocha": ">=10.0.6", + "@types/node": ">=20.11.19", + "chai": "^4.3.7", + "codecov": "^3.8.3", + "ethers": "^6.11.1", + "forge-std": "github:foundry-rs/forge-std#v1.7.6", + "modulekit": "github:rhinestonewtf/modulekit", + "hardhat-gas-reporter": "^1.0.10", + "hardhat-storage-layout": "^0.1.7", + "prettier": "^3.2.5", + "prettier-plugin-solidity": "^1.3.1", + "solhint": "^4.1.1", + "solhint-plugin-prettier": "^0.1.0", + "solidity-coverage": "^0.8.7", + "ts-node": ">=10.9.2", + "typechain": "^8.3.2", + "typescript": ">=5.3.3" + }, + "keywords": [ + "blockchain", + "ethereum", + "forge", + "foundry", + "hardhat", + "smart-contracts", + "solidity" + ], + "private": true, + "scripts": { + "clean:forge": "forge clean", + "clean:hardhat": "yarn hardhat clean", + "clean": "yarn run clean:forge && yarn run clean:hardhat && rm -rf cache docs coverage storageLayout coverage.json", + "build:forge": "forge build", + "build:hardhat": "yarn hardhat compile", + "build": "yarn run build:forge && yarn run build:hardhat", + "test:forge": "forge test", + "test:hardhat": "yarn hardhat test", + "test": "yarn run test:hardhat && yarn run test:forge", + "test:gas:forge": "forge test --gas-report", + "test:gas:hardhat": "REPORT_GAS=true hardhat test", + "test:gas": "yarn test:gas:hardhat && yarn test:gas:forge", + "coverage:forge": "forge coverage", + "coverage:hardhat": "yarn hardhat coverage", + "coverage": "yarn run coverage:forge && yarn run coverage:hardhat", + "coverage:report": "forge coverage --report lcov && genhtml lcov.info --branch-coverage --output-dir coverage/foundry && mv lcov.info coverage/foundry && yarn run coverage:hardhat", + "docs": "yarn hardhat docgen", + "check-storage": "yarn hardhat check", + "deploy:hardhat": "yarn hardhat run --network localhost scripts/typescript/deploy.ts", + "deploy:forge": "forge script scripts/solidity/Deploy.s.sol --broadcast --rpc-url http://localhost:8545", + "lint:sol": "yarn solhint 'contracts/**/*.sol' && forge fmt --check", + "lint:sol-fix": "yarn prettier --write 'contracts/**/*.sol' && yarn solhint 'contracts/**/*.sol' --fix --noPrompt && forge fmt", + "lint:ts": "yarn prettier --check 'test/**/*.ts' 'scripts/**/*.ts'", + "lint:ts-fix": "yarn prettier --write 'test/**/*.ts' 'scripts/**/*.ts'", + "lint": "yarn run lint:sol && yarn run lint:ts", + "lint:fix": "yarn run lint:sol-fix && yarn run lint:ts-fix" + } +} diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 00000000..e91ca095 --- /dev/null +++ b/remappings.txt @@ -0,0 +1,4 @@ +@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ +@prb/test/=node_modules/@prb/test/ +forge-std/=node_modules/forge-std/ +modulekit/=node_modules/modulekit/src/ \ No newline at end of file diff --git a/scripts/foundry/Base.s.sol b/scripts/foundry/Base.s.sol new file mode 100644 index 00000000..794d2de1 --- /dev/null +++ b/scripts/foundry/Base.s.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.23 <0.9.0; + +import { Script } from "forge-std/src/Script.sol"; + +abstract contract BaseScript is Script { + /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. + string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; + + /// @dev Needed for the deterministic deployments. + bytes32 internal constant ZERO_SALT = bytes32(0); + + /// @dev The address of the transaction broadcaster. + address internal broadcaster; + + /// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined. + string internal mnemonic; + + /// @dev Initializes the transaction broadcaster like this: + /// + /// - If $ETH_FROM is defined, use it. + /// - Otherwise, derive the broadcaster address from $MNEMONIC. + /// - If $MNEMONIC is not defined, default to a test mnemonic. + /// + /// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line. + constructor() { + address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); + if (from != address(0)) { + broadcaster = from; + } else { + mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC }); + (broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 }); + } + } + + modifier broadcast() { + vm.startBroadcast(broadcaster); + _; + vm.stopBroadcast(); + } +} diff --git a/scripts/foundry/Deploy.s.sol b/scripts/foundry/Deploy.s.sol new file mode 100644 index 00000000..2c5a4a64 --- /dev/null +++ b/scripts/foundry/Deploy.s.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.23 <0.9.0; + +import { Foo } from "../../contracts/Foo.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting +contract Deploy is BaseScript { + function run() public broadcast returns (Foo foo) { + foo = new Foo(); + } + + function test() public pure returns (uint256) { + return 0; + } +} diff --git a/scripts/hardhat/deploy.ts b/scripts/hardhat/deploy.ts new file mode 100644 index 00000000..aec5b4cb --- /dev/null +++ b/scripts/hardhat/deploy.ts @@ -0,0 +1,27 @@ +import { ethers } from "hardhat"; + +async function main() { + const currentTimestampInSeconds = Math.round(Date.now() / 1000); + const unlockTime = currentTimestampInSeconds + 60; + + const lockedAmount = ethers.parseEther("0.001"); + + const lock = await ethers.deployContract("Lock", [unlockTime], { + value: lockedAmount, + }); + + await lock.waitForDeployment(); + + console.log( + `Lock with ${ethers.formatEther( + lockedAmount, + )}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}`, + ); +} + +// We recommend this pattern to be able to use async/await everywhere +// and properly handle errors. +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/test/foundry/Foo.t.sol b/test/foundry/Foo.t.sol new file mode 100644 index 00000000..5ff564e3 --- /dev/null +++ b/test/foundry/Foo.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.23 <0.9.0; + +import { PRBTest } from "@prb/test/src/PRBTest.sol"; +import { console2 } from "forge-std/src/console2.sol"; +import { StdCheats } from "forge-std/src/StdCheats.sol"; +import { Foo } from "../../contracts/Foo.sol"; + +interface IERC20 { + function balanceOf(address account) external view returns (uint256); +} + +/// @dev If this is your first time with Forge, read this tutorial in the Foundry Book: +/// https://book.getfoundry.sh/forge/writing-tests +contract FooTest is PRBTest, StdCheats { + Foo internal foo; + + /// @dev A function invoked before each test case is run. + function setUp() public virtual { + // Instantiate the contract-under-test. + foo = new Foo(); + } + + /// @dev Basic test. Run it with `forge test -vvv` to see the console log. + function testExample() public { + console2.log("Hello World"); + uint256 x = 42; + assertEq(foo.id(x), x, "value mismatch"); + } + + /// @dev Fuzz test that provides random values for an unsigned integer, but which rejects zero as an input. + /// If you need more sophisticated input validation, you should use the `bound` utility instead. + /// See https://twitter.com/PaulRBerg/status/1622558791685242880 + function testFuzzExample(uint256 x) public { + vm.assume(x != 0); // or x = bound(x, 1, 100) + assertEq(foo.id(x), x, "value mismatch"); + } + + /// @dev Fork test that runs against an Ethereum Mainnet fork. For this to work, you need to set `API_KEY_ALCHEMY` + /// in your environment You can get an API key for free at https://alchemy.com. + function testForkExample() public { + // Silently pass this test if there is no API key. + string memory alchemyApiKey = vm.envOr("API_KEY_ALCHEMY", string("")); + if (bytes(alchemyApiKey).length == 0) { + return; + } + + // Otherwise, run the test against the mainnet fork. + vm.createSelectFork({ urlOrAlias: "mainnet", blockNumber: 16_428_000 }); + address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address holder = 0x7713974908Be4BEd47172370115e8b1219F4A5f0; + uint256 actualBalance = IERC20(usdc).balanceOf(holder); + uint256 expectedBalance = 196_307_713.810457e6; + assertEq(actualBalance, expectedBalance); + } +} diff --git a/test/foundry/Lock.t.sol b/test/foundry/Lock.t.sol new file mode 100644 index 00000000..858622f4 --- /dev/null +++ b/test/foundry/Lock.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.24 <0.9.0; + +import { PRBTest } from "@prb/test/src/PRBTest.sol"; +import { Lock } from "../../contracts/Lock.sol"; +import { StdCheats } from "forge-std/src/StdCheats.sol"; + +contract LockTest is PRBTest, StdCheats { + Lock public lock; + address payable owner; + + receive() external payable { } + + function setUp() public { + owner = payable(address(this)); + uint256 unlockTime = block.timestamp + 1 days; // Set unlock time to 1 day from now + lock = new Lock{ value: 1 ether }(unlockTime); + } + + function testInitialOwner() public { + assertEq(lock.owner(), owner); + } + + function testWithdrawal() public { + // Fast forward time to surpass the unlockTime + vm.warp(block.timestamp + 2 days); + + uint256 initialBalance = address(this).balance; + lock.withdraw(); + uint256 finalBalance = address(this).balance; + + // Check if the contract's balance was transferred to the owner + assertGt(finalBalance, initialBalance); + } + + function testWithdrawTooEarly() public { + // This test is expected to fail as the withdrawal is too early + vm.expectRevert(bytes("You can't withdraw yet")); + lock.withdraw(); + } + + function testWithdrawByNonOwner() public { + // Change the sender to someone other than the owner + vm.warp(block.timestamp + 2 days); + vm.prank(address(0x123)); + vm.expectRevert(bytes("You aren't the owner")); + lock.withdraw(); + } +} diff --git a/test/hardhat/Foo.ts b/test/hardhat/Foo.ts new file mode 100644 index 00000000..badb63c1 --- /dev/null +++ b/test/hardhat/Foo.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { Foo } from "../../typechain-types"; + +describe("Foo contract", function () { + let foo: Foo; + + beforeEach(async function () { + // Deploy the Foo contract before each test + const Foo = await ethers.getContractFactory("Foo"); + foo = await Foo.deploy(); + }); + + // Test case for the id function + it("should return the same value passed", async function () { + const testValue = 123; + expect(await foo.id(testValue)).to.equal(testValue); + }); +}); diff --git a/test/hardhat/Lock.ts b/test/hardhat/Lock.ts new file mode 100644 index 00000000..98693fe1 --- /dev/null +++ b/test/hardhat/Lock.ts @@ -0,0 +1,127 @@ +import { + time, + loadFixture, +} from "@nomicfoundation/hardhat-toolbox/network-helpers"; +import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs"; +import { expect } from "chai"; +import { ethers } from "hardhat"; + +describe("Lock", function () { + // We define a fixture to reuse the same setup in every test. + // We use loadFixture to run this setup once, snapshot that state, + // and reset Hardhat Network to that snapshot in every test. + async function deployOneYearLockFixture() { + const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; + const ONE_GWEI = 1_000_000_000; + + const lockedAmount = ONE_GWEI; + const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; + + // Contracts are deployed using the first signer/account by default + const [owner, otherAccount] = await ethers.getSigners(); + + const Lock = await ethers.getContractFactory("Lock"); + const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); + + return { lock, unlockTime, lockedAmount, owner, otherAccount }; + } + + describe("Deployment", function () { + it("Should set the right unlockTime", async function () { + const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); + + expect(await lock.unlockTime()).to.equal(unlockTime); + }); + + it("Should set the right owner", async function () { + const { lock, owner } = await loadFixture(deployOneYearLockFixture); + + expect(await lock.owner()).to.equal(owner.address); + }); + + it("Should receive and store the funds to lock", async function () { + const { lock, lockedAmount } = await loadFixture( + deployOneYearLockFixture, + ); + + expect(await ethers.provider.getBalance(lock.target)).to.equal( + lockedAmount, + ); + }); + + it("Should fail if the unlockTime is not in the future", async function () { + // We don't use the fixture here because we want a different deployment + const latestTime = await time.latest(); + const Lock = await ethers.getContractFactory("Lock"); + await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith( + "Wrong Unlock time", + ); + }); + }); + + describe("Withdrawals", function () { + describe("Validations", function () { + it("Should revert with the right error if called too soon", async function () { + const { lock } = await loadFixture(deployOneYearLockFixture); + + await expect(lock.withdraw()).to.be.revertedWith( + "You can't withdraw yet", + ); + }); + + it("Should revert with the right error if called from another account", async function () { + const { lock, unlockTime, otherAccount } = await loadFixture( + deployOneYearLockFixture, + ); + + // We can increase the time in Hardhat Network + await time.increaseTo(unlockTime); + + // We use lock.connect() to send a transaction from another account + await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( + "You aren't the owner", + ); + }); + + it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () { + const { lock, unlockTime } = await loadFixture( + deployOneYearLockFixture, + ); + + // Transactions are sent using the first signer by default + await time.increaseTo(unlockTime); + + await expect(lock.withdraw()).not.to.be.reverted; + }); + }); + + describe("Events", function () { + it("Should emit an event on withdrawals", async function () { + const { lock, unlockTime, lockedAmount } = await loadFixture( + deployOneYearLockFixture, + ); + + await time.increaseTo(unlockTime); + + await expect(lock.withdraw()) + .to.emit(lock, "Withdrawal") + .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg + }); + }); + + describe("Transfers", function () { + it("Should transfer the funds to the owner", async function () { + const { lock, unlockTime, lockedAmount, owner } = await loadFixture( + deployOneYearLockFixture, + ); + + await time.increaseTo(unlockTime); + + await expect(lock.withdraw()).to.changeEtherBalances( + [owner, lock], + [lockedAmount, -lockedAmount], + ); + }); + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..574e785c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } +}