diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b79c8d4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,38 @@ +name: CI + +permissions: {} + +on: + push: + pull_request: + workflow_dispatch: + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + name: Foundry project + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Show Forge version + run: forge --version + + - name: Run Forge fmt + run: forge fmt --check + + - name: Run Forge build + run: forge build --sizes + + - name: Run Forge tests + run: forge test -vvv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85198aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..888d42d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/README.md b/README.md new file mode 100644 index 0000000..8817d6a --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +## Foundry + +**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/foundry.lock b/foundry.lock new file mode 100644 index 0000000..bc06b89 --- /dev/null +++ b/foundry.lock @@ -0,0 +1,8 @@ +{ + "lib/forge-std": { + "tag": { + "name": "v1.15.0", + "rev": "0844d7e1fc5e60d77b68e469bff60265f236c398" + } + } +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000..c127727 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,10 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] +solc = "0.8.28" +evm_version = "cancun" + +[rpc_endpoints] +base = "https://mainnet.base.org" +base_sepolia = "https://sepolia.base.org" diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 0000000..0844d7e --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 0844d7e1fc5e60d77b68e469bff60265f236c398 diff --git a/src/StoryFactory.sol b/src/StoryFactory.sol new file mode 100644 index 0000000..a2ee865 --- /dev/null +++ b/src/StoryFactory.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {IMCV2_Bond} from "./interfaces/IMCV2_Bond.sol"; +import {IERC20} from "./interfaces/IERC20.sol"; + +/// @title StoryFactory — PlotLink storyline and plot management +/// @notice Placeholder — full implementation in subsequent tickets +contract StoryFactory { + IMCV2_Bond public immutable BOND; + IERC20 public immutable PLOT_TOKEN; + + constructor(address _bond, address _plotToken) { + BOND = IMCV2_Bond(_bond); + PLOT_TOKEN = IERC20(_plotToken); + } +} diff --git a/src/interfaces/IERC20.sol b/src/interfaces/IERC20.sol new file mode 100644 index 0000000..172505e --- /dev/null +++ b/src/interfaces/IERC20.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +/// @title IERC20 — Minimal ERC-20 interface for StoryFactory interactions +interface IERC20 { + function approve(address spender, uint256 amount) external returns (bool); + function transfer(address to, uint256 amount) external returns (bool); + function transferFrom(address from, address to, uint256 amount) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function allowance(address owner, address spender) external view returns (uint256); +} diff --git a/src/interfaces/IMCV2_Bond.sol b/src/interfaces/IMCV2_Bond.sol new file mode 100644 index 0000000..6875e24 --- /dev/null +++ b/src/interfaces/IMCV2_Bond.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +/// @title IMCV2_Bond — Interface for Mint Club V2 Bond contract on Base +/// @dev Deployed at 0xc5a076cad94176c2996B32d8466Be1cE757FAa27 +/// @dev Source: github.com/Steemhunt/mint.club-v2-contract + +struct TokenParams { + string name; + string symbol; +} + +struct BondParams { + uint16 mintRoyalty; + uint16 burnRoyalty; + address reserveToken; + uint128 maxSupply; + uint128[] stepRanges; + uint128[] stepPrices; +} + +interface IMCV2_Bond { + /// @notice Create a new ERC-20 token with bonding curve + function createToken(TokenParams calldata tp, BondParams calldata bp) external payable returns (address); + + /// @notice Transfer the creator role (royalty recipient) for a token + function updateBondCreator(address token, address creator) external; + + /// @notice Mint tokens on the bonding curve + /// @return reserveAmount Amount of reserve token spent + function mint(address token, uint256 tokensToMint, uint256 maxReserveAmount, address receiver) + external + returns (uint256); + + /// @notice Burn tokens on the bonding curve + /// @return refundAmount Amount of reserve token refunded + function burn(address token, uint256 tokensToBurn, uint256 minRefund, address receiver) external returns (uint256); + + /// @notice Get the reserve amount required to mint tokens + function getReserveForToken(address token, uint256 tokensToMint) + external + view + returns (uint256 reserveAmount, uint256 royalty); + + /// @notice Get the refund for burning tokens + function getRefundForTokens(address token, uint256 tokensToBurn) + external + view + returns (uint256 refundAmount, uint256 royalty); + + /// @notice Claim accumulated royalties (inherited from MCV2_Royalty) + function claimRoyalties(address reserveToken) external; +}