Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Foundry smart contracts #13

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "Foundry_Contracts/lib/forge-std"]
path = Foundry_Contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
45 changes: 45 additions & 0 deletions Foundry_Contracts/.github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

env:
FOUNDRY_PROFILE: ci

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Show Forge version
run: |
forge --version

- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge build --sizes
id: build

- name: Run Forge tests
run: |
forge test -vvv
id: test
14 changes: 14 additions & 0 deletions Foundry_Contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Compiler files
cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/

# Docs
docs/

# Dotenv file
.env
71 changes: 71 additions & 0 deletions Foundry_Contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## 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

### Download openzeppelin/contracts
```shell
$ forge install @openzeppelin/contracts
```

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```bash
forge script script/DeployEthpreneur.s.sol --fork-url http://localhost:8545 --private-key <PRIVATE_KEY> --broadcast
```

### Cast

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
115 changes: 115 additions & 0 deletions Foundry_Contracts/WorkingEthPreneur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Ethpreneur1155 and EthStock Contracts

## Overview
The `Ethpreneur1155` contract allows companies to register and create their own stock contracts based on ERC1155, enabling stock creation, buying, and selling functionalities. The `EthStock` contract handles the stock management (supply, pricing, and transfers).

## Contracts

### `EthStock`
This contract is an implementation of the ERC1155 token standard, representing a company’s stocks as fungible tokens. The contract allows companies to create and manage their stocks, enabling functionalities like creating, buying, and selling stock types.

#### Key Features:
- **Create Stock**: Allows a company to create new stocks with an initial supply and price.
- **Add Stock Supply**: Adds additional supply to existing stock types.
- **Buy Stock**: Allows buyers to purchase stocks from the company by transferring ETH.
- **Sell Stock**: Allows stockholders to sell their stocks back to the company for ETH.

#### Functions:

- **`createStock(uint256 _price, uint256 _initialSupply)`**: Allows the company owner to create a new stock type with an initial supply and price.

- **`addStocks(uint256 sType, uint256 supply)`**: Increases the supply of a specific stock type.

- **`buyStock(address buyer, uint256 sType, uint256 amount)`**: Facilitates the buying of stocks by transferring ownership from the company to the buyer. Requires payment to match the total price of the stocks.

- **`sellStock(address seller, uint256 sType, uint256 amount)`**: Allows stockholders to sell their stocks back to the company in exchange for ETH.

- **`getStockDetails(uint256 sType)`**: Returns details about a specific stock type, including its total supply, available supply, and price.

- **`getStockPrice(uint256 sType)`**: Retrieves the price of a specific stock type.

- **`getAvailableSupply(uint256 sType)`**: Returns the available supply of a specific stock type.

#### Events:
- **`StockCreated(address stockContract, uint256 stockType)`**: Emitted when a new stock is created.

- **`StockBought(address indexed buyer, uint256 stockType, uint256 amount)`**: Emitted when stocks are bought.

- **`StockSold(address indexed seller, uint256 stockType, uint256 amount)`**: Emitted when stocks are sold.

#### Errors:
- **`Stock__NotEnoughStocks()`**: Thrown when attempting to buy or sell more stocks than are available or owned.
- **`Stock__IncorrectPayment()`**: Thrown when the payment amount doesn't match the total cost of the stocks.

### `Ethpreneur1155`
This contract allows companies to register themselves and create their own stock contracts using the `EthStock` contract. It acts as a registry and controller for multiple companies and their respective stock contracts.

#### Key Features:
- **Company Registration**: A company can register itself and create a stock contract.
- **Create Stock**: Registered companies can create their stocks.
- **Buy and Sell Stock**: Facilitates buying and selling of stocks for registered companies.

#### Functions:

- **`registerCompany(string memory uri)`**: Allows a company to register and deploy a new `EthStock` contract for managing their stocks.

- **`createCompanyStock(uint256 _initialSupply, uint256 _price)`**: Allows a registered company to create a new stock type.

- **`buyCompanyStock(address _company, uint256 stockType, uint256 _amount)`**: Enables users to buy stocks from a company's stock contract by paying the required ETH amount.

- **`sellCompanyStock(address _company, uint256 stockType, uint256 _amount)`**: Allows users to sell stocks back to the company's stock contract in exchange for ETH.

- **`getCompanyStockContract(address company)`**: Retrieves the address of a company's `EthStock` contract.

- **`getCompanyStockPrice(address _company, uint256 stockType)`**: Returns the price of a specific stock type for a given company.

- **`getCompanyAvailableStocks(address _company, uint256 stockType)`**: Retrieves the available supply of a stock type for a given company.

- **`getTotalTypeOfStocks(address _company)`**: Returns the total number of stock types created by a company.

#### Events:
- **`CompanyCreated(address indexed owner, address stockContract)`**: Emitted when a new company registers and creates its stock contract.

- **`StockCreated(address stockContract, uint256 stockType)`**: Emitted when a new stock type is created.

- **`StockBought(address indexed buyer, uint256 stockType, uint256 amount)`**: Emitted when a buyer purchases stocks.

- **`StockSold(address indexed seller, uint256 stockType, uint256 amount)`**: Emitted when stocks are sold back to the company.

#### Errors:
- **`EthPreneur__NoStockContract()`**: Thrown when trying to interact with a company that hasn't registered a stock contract.
- **`EthPreneur__NoStock()`**: Thrown when trying to interact with a non-existent stock type.
- **`EthPreneur__InvalidStockType()`**: Thrown when referencing an invalid stock type.
- **`EthPreneur__NotEnoughStockAvailable()`**: Thrown when trying to buy more stocks than are available.
- **`EthPreneur__IncorrectPayment()`**: Thrown when the buyer doesn't send the correct payment amount.
- **`EthPreneur__CompanyAlreadyCreatedStock()`**: Thrown when a company tries to register after already creating a stock contract.
- **`EthPreneur__CompanyAlreadyHasStock()`**: Thrown when trying to create a stock contract when one already exists.

## Usage Example

1. **Register a Company**:
A company can register by calling `registerCompany(uri)` and passing a URI for metadata. This will deploy a new `EthStock` contract for the company.

```solidity
ethpreneur.registerCompany("https://example.com/metadata");
```

2. **Create Stock**:
After registering, the company can create a new stock type by calling createCompanyStock(initialSupply, price).

```solidity
ethpreneur.createCompanyStock(1000, 1 ether);
```
3. **Buy Stock**:
Users can buy stocks from the company by calling buyCompanyStock with the amount of stocks they want to buy and the price of each stock.

```solidity
ethpreneur.buyCompanyStock(companyAddress, stockType, amount, { value: price * amount });
```

4. **Sell Stock**:
Users can sell their stocks back to the company by calling sellCompanyStock.

```solidity
ethpreneur.sellCompanyStock(companyAddress, stockType, amount);
```
11 changes: 11 additions & 0 deletions Foundry_Contracts/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
remappings=[
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
]
fs_permissions = [{access = "read", path = "./"}]
solc = "0.8.28" # Replace with the version you want, e.g., 0.8.21

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions Foundry_Contracts/lib/forge-std
Submodule forge-std added at 8f24d6
16 changes: 16 additions & 0 deletions Foundry_Contracts/script/DeployEthpreneur.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Script} from "forge-std/Script.sol";
import {Ethpreneur1155} from "../src/Ethpreneur1155.sol";

contract Deploy is Script {
Ethpreneur1155 ethpre;

function run() public returns (Ethpreneur1155) {
vm.startBroadcast(msg.sender);
ethpre = new Ethpreneur1155();
vm.stopBroadcast();
return ethpre;
}
}
111 changes: 111 additions & 0 deletions Foundry_Contracts/src/EthStock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract EthStock is ERC1155, Ownable {

// Stocks structure to hold details of each stock type
struct Stocks{
uint256 totalSupply;
uint256 availableSupply;
uint256 price;
}

mapping(uint256 => Stocks) private typeToStocks; // Mapping of type of stock to details of stock
uint256 private stockType;
address public companyOwner;

//////////// ERRORS ////////////
error Stock__NotEnoughStocks();
error Stock__IncorrectPayment();



//////////// CONSTRUCTOR ////////////
// Constructor called when contract is created
constructor(string memory _uri, address _owner) ERC1155(_uri) Ownable(msg.sender) {
companyOwner = _owner;
stockType=0;
}

//////////// FUNCTIONS ////////////
// Create stock with initial(total) supply and price
function createStock(uint256 _price, uint256 _initialSupply) external onlyOwner {
Stocks memory newStock = Stocks({
totalSupply: _initialSupply,
availableSupply: _initialSupply,
price: _price
});
typeToStocks[stockType] = newStock;
_mint(companyOwner, stockType, _initialSupply, "");
stockType++;
}

// Function to add stocks to the existing stock type
function addStocks(uint256 sType, uint256 supply) external onlyOwner {
typeToStocks[sType].availableSupply+=supply;
typeToStocks[sType].totalSupply+=supply;
}

// Buy stocks
function buyStock(address buyer, uint256 sType, uint256 amount) external payable onlyOwner {
uint256 price = getStockPrice(sType);
uint256 availableSupply = getAvailableSupply(sType);
uint256 totalPrice = price * amount;
require(msg.value == totalPrice, Stock__IncorrectPayment());
require(amount <= availableSupply, Stock__NotEnoughStocks());
boughtStock(sType, amount);
_safeTransferFrom(companyOwner, buyer, sType, amount, "");
}

// Sell stocks
function sellStock(address seller, uint256 sType, uint256 amount) external onlyOwner {
require(balanceOf(seller, sType) >= amount, Stock__NotEnoughStocks());
uint256 stockPrice = getStockPrice(sType);
uint256 totalPrice = stockPrice * amount;
_safeTransferFrom(seller, companyOwner, sType, amount, "");
soldStock(sType, amount);
payable(seller).transfer(totalPrice);
}

// Decrease stock by amount
function boughtStock(uint256 sType, uint256 amount) internal {
typeToStocks[sType].availableSupply-=amount;
}

// Increase stock by amount
function soldStock(uint256 sType, uint256 amount) internal {
typeToStocks[sType].availableSupply+=amount;
}

// Get stock details from its type
function getStockDetails(uint256 sType) public view returns (uint256, uint256, uint256) {
Stocks memory stock = typeToStocks[sType];
return (stock.totalSupply, stock.availableSupply, stock.price);
}

// Retrieve price of the stock
function getStockPrice(uint256 sType) public view returns (uint256) {
(,, uint256 price) = getStockDetails(sType);
return price;
}

// Retrieve total supply of the stock
function getTotalSupply(uint256 sType) public view returns (uint256) {
(uint256 totalSupply, , ) = getStockDetails(sType);
return totalSupply;
}

// Retrieve available supply of the stock
function getAvailableSupply(uint256 sType) public view returns (uint256) {
(, uint256 availableSupply, ) = getStockDetails(sType);
return availableSupply;
}

// Get total type of stocks available
function getTotalTypeOfStocks() public view returns(uint256) {
return stockType;
}
}
Loading