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

SuperMinter #294

Merged
merged 4 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Update README
  • Loading branch information
Vectorized committed Sep 28, 2023
commit 0de33708a7480e181986d7bd410e3a25f77174ac
217 changes: 47 additions & 170 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,30 @@ Sound Protocol is a generalized platform for flexible and efficient creation of
- [Sound Protocol](#sound-protocol)
- [Table of Contents](#table-of-contents)
- [Deployments](#deployments)
- [Specification](#specification)
- [Architecture](#architecture)
- [Diagram](#diagram)
- [Contracts](#contracts)
- [Documentation](#documentation)
- [Usage](#usage)
- [Prerequisites](#prerequisites)
- [Setup](#setup)
- [Testing](#testing)
- [Deploying](#deploying)
- [Development](#development)
- [Deploying](#deploying)
- [Bug Bounty](#bug-bounty)
- [License](#license)

## Deployments

`SoundCreatorV1` Factory contract
| Network | Address |
|---|---|
| `Mainnet` | 0xaef3e8c8723d9c31863be8de54df2668ef7c4b89
| `Goerli` | 0xaef3e8c8723d9c31863be8de54df2668ef7c4b89
| `Optimism` | 0x5bcf5773bcf1f131a0cad5c74aa9be1a80b63c55


Permissionless zero-fee minter/metadata deployments on Mainnet, Goerli, Optimism, and Optimism Goerli:
The following contracts have been deployed on Mainnet, Optimism, Goerli, Optimism-Goerli, and Sepolia.

| Contract | Address |
|---|---|
| `GoldenEggMetadata` | 0x000000002154ad3431c330ac2db6ed42195f9141
| `OpenGoldenEggMetadata` | 0x00000000c417a48cd096067520747607a0331f0e
| `MerkleDropMinter` | 0x0000000067149f4d5e7d2904179b8fccca000539
| `RangeEditionMinter` | 0x000000006154a95522e183f4d85bb7f2cd666ae8




## Specification

See [spec](./spec.md) for current protocol specification. For details on how to build and run a custom minter instance, see section ["Adding a custom minter module"](./spec.md#adding-a-custom-minter-module) section in spec. Documentation coming soon.
| `SoundEditionV2` | 0x0000000000c78FEE168002D89D141517b8E6E0FE
| `SoundCreatorV2` | 0x0000000000aec84F5BFc2af15EAfb943bf4e3522
| `SuperMinter` | 0x0000000000CF4558c36229ac0026ee16D3aE35Cd
| `SoundOnChainMetadata` | 0x0000000000724868d80283B098Ffa809B2181692
| `SoundMetadata` | 0x0000000000f5A96Dc85959cAeb0Cfe680f108FB5

## Architecture

The Sound Protocol comprises of several components:
The latest Sound Protocol comprises of several components:

- **`SoundEdition`**
- **`SoundEditionV2`**

The NFT contract.

Expand All @@ -59,182 +39,79 @@ The Sound Protocol comprises of several components:
The `mint` function allows authorized minter contracts or administrators to batch mint NFTs
(authorization is granted via the `MINTER_ROLE` or `ADMIN_ROLE`).

- **`SoundCreator`**
- **`SoundCreatorV2`**

A factory that allows for a single transaction setup that:
1. Deploys and initializes `SoundEdition`.
2. Authorize one or more `MinterContract`s on `SoundEdition`.
3. Configure one or more `MinterContract`s to mint on `SoundEdition`.

- **`MinterContract`**

A contract to call the `mint` function on `SoundEdition`.
This contract can implement any kind of customized sales logic.
One or more `MinterContract`s can be used on the `SoundEdition` simultaneously.
1. Clones and initializes a `SoundEdition`.
2. Forwards calldata to an array of target contracts. These calldata can be used to set up the required authorizations and mint schedules.

- **`fundingRecipient`**
- **`SuperMinter`**

Can be a contract such as a [0xSplits](https://github.com/0xSplits/splits-contracts) wallet, or an Externally Owned Account (EOA).
A generalized singleton minter contract that can mint on `SoundEdition`s.

- **`MetadataContract`**
Technically, any contract can be authorized to mint on a `SoundEdition` as long as they are granted the `MINTER_ROLE`.

A contract which is called by the `SoundEdition` in the `tokenURI` function for customizable metadata logic.
Optional.

## Diagram
- **`SoundMetadata`**

```mermaid
flowchart LR
SoundCreatorV1 --> initialize
A contract which is called by the `SoundEdition` in the `tokenURI` function for customizable metadata logic. The on-chain JSON variant is called `SoundOnChainMetadata`.

subgraph SoundEditionV1
initialize
mint
withdrawETH
withdrawERC20
tokenURI
end

tokenURI -.-> MetadataContract
A[Minter A] --> mint
B[Minter B] --> mint
C[Minter C] --> mint
withdrawETH --> fundingRecipient
withdrawERC20 --> fundingRecipient
```

## Contracts

The smart contracts are stored under the `contracts` directory.

Files marked with an asterisk (\*) are specific to [sound.xyz](https://sound.xyz),
but you can refer to them if you are building contracts to interact with them on-chain,
or building your own customized versions.
These are the contracts currently used. The actual directories may contain some older contracts not on the list, as they are left there for backwards compatibility.

```ml
contracts/
├── core
│  ├── SoundCreatorV1.sol ─ "Factory"
│  ├── SoundEditionV1.sol ─ "NFT implementation"
│  ├── SoundFeeRegistry.sol * ─ "Platform fee registry"
│  ├── SoundCreatorV2.sol ─ "Factory"
│  ├── SoundEditionV2.sol ─ "NFT implementation"
│  ├── interfaces
│  │ ├── IMetadataModule.sol ─ "Metadata module interface"
│  │ ├── IMinterModule.sol ─ "Generalized minter interface"
│  │ ├── ISoundCreatorV1.sol ─ "Factory interface"
│  │ ├── ISoundEditionV1.sol ─ "NFT implementation interface"
│  │ └── ISoundFeeRegistry.sol * ─ "Platform fee registry interface"
│  │ ├── ISoundCreatorV2.sol
│  │ └── ISoundEditionV2.sol
│  └── utils
│  └── ArweaveURILib.sol * ─ "For efficient storage of Arweave URIs"
│ ├── MintRandomnessLib.sol ─ "Library for on-chain 1-of-1 raffle"
│ ├── LibOps.sol ─ "Library for common operations"
│  └── ArweaveURILib.sol ─ "For efficient storage of Arweave URIs"
└── modules
├── BaseMinter.sol * ─ "Shared minting logic"
├── EditionMaxMinter.sol * ─ "Minimalistic minter"
├── FixedPriceSignatureMinter.sol * ─ "For permissioned mints via ECDSA signatures"
├── MerkleDropMinter.sol * ─ "For permissioned mints via Merkle proofs"
├── RangeEditionMinter.sol * ─ "Cuts off mints after a set time if a quota is hit"
├── GoldenEggMetadata.sol * ─ "For the on-chain golden egg metadata"
└── interfaces
├── IEditionMaxMinter.sol *
├── IFixedPriceSignatureMinter.sol *
├── IMerkleDropMinter.sol *
├── IRangeEditionMinter.sol *
└── IGoldenEggMetadata.sol *
├── SuperMinter.sol ─ "Generalized minter"
├── SoundMetadata.sol ─ "Metadata module for SoundEdition"
├── SoundOnChainMetadata.sol ─ "On-chain variant of SoundMetadata"
├── interfaces
│ ├── ISuperMinter.sol
│ ├── ISoundMetadata.sol
│ └── ISoundOnChainMetadata.sol
  └── utils
├── DelegateCashLib.sol ─ "Library for querying with DelegateCash"
  └── SoundOnChainMetadataLib.sol ─ "Library for SoundOnChainMetadata"
```

## Documentation

A comprehensive documentation is currently in the works.

Please refer to the Natspec comments and [spec](./spec.md) for now for further details.

## Usage

### Prerequisites

- [git](https://git-scm.com/downloads)
- [nodeJS](https://nodejs.org/en/download/)
- [node version manager](https://github.com/nvm-sh/nvm)
- [pnpm](https://pnpm.io/) - You need to have `pnpm` installed globally, you can run `npm i -g pnpm` to install it.
- [brew](https://brew.sh/)
- [foundry](https://getfoundry.sh) - You can run `sh ./setup.sh` to install Foundry and its dependencies.

### Setup

- Clone the repository

```bash
git clone git@github.com:soundxyz/sound-protocol.git
cd sound-protocol
```

- Setup node version
Either install the version specified in `nvmrc` or use `nvm` to set it up:
The documentation for the latest contracts is under construction.

```
nvm use
```
For now, you can refer to the Natspec.

- Install packages
## Development

```
pnpm install
```
This is a [foundry](https://getfoundry.sh) based project.

- Build contracts
However, some of the directories differ from the defaults.

```
pnpm build
```
- The contracts are under `contracts`.
- The tests are under `tests`.

- Run tests
## Deploying

```
pnpm test
```
The contracts have already been deployed to their canonical addresses.

- Print gas reports from tests

```
pnpm test:gas
```

### Testing

(`v` == logs verbosity)

`forge test -vvv`

**Code coverage:**

We use [codecov](https://app.codecov.io/gh/soundxyz/sound-protocol/) for analysing the code coverage reports generated by forge coverage. To view code coverage locally, you'll need to install `lcov` (mac: `brew install lcov`) and run:

```
pnpm test:coverage
```

This will produce the coverage report in `/coverage` folder. Note that `forge coverage` is still in active development so it often claims if/else branches are uncovered even when there are tests executed on them.

### Deploying

Create a .env in the root with:

```
GOERLI_RPC_URL=
MAINNET_RPC_URL=
PRIVATE_KEY=
ETHERSCAN_KEY=
OWNER=<address that will own the ownable contracts>
```

Then run:

```
pnpm deploy:goerli
```
If you need them on any other EVM based chain, please look into `build_create2_deployments.sh`.

## Bug Bounty

Up to 10 ETH for any critical bugs that could result in loss of funds. Rewards will be given for smaller bugs or ideas.

## License

[MIT](LICENSE) Copyright 2022 Sound.xyz
[MIT](LICENSE) Copyright 2023 Sound.xyz
63 changes: 63 additions & 0 deletions build_create2_deployments.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Download the libs if they aren't yet downloaded.
forge install;

# Create the create2 deployments directory.
mkdir create2 > /dev/null 2>&1;

# Use a temporary directory.
mkdir .tmp > /dev/null 2>&1;
rm -rf .tmp/contracts > /dev/null 2>&1;
rm -rf .tmp/lib > /dev/null 2>&1;
cp -r contracts .tmp/contracts;
cp -r foundry.toml .tmp/foundry.toml;
cp -r remappings.txt .tmp/remappings.txt;
cp -r lib .tmp/lib;

# Go into the temporary directory.
cd .tmp;

# Build the Solidity files.
forge build --out="out" --root=".";

# Install some files for computing the initcodehash.
echo '{ "devDependencies": { "@ethersproject/keccak256": "5.7.0" } }' > package.json;
if [ ! -f package-lock.json ]; then npm install; fi

# Create the deployments directory in the temporary directory.
mkdir create2 > /dev/null 2>&1;

# Function to generate the deployment files.
generateDeployment() {
rm -rf "create2/$1" > /dev/null 2>&1;
mkdir "create2/$1" > /dev/null 2>&1;
# Generate the js file to do the hard work.
echo "
const fs = require(\"fs\"),
rfs = s => fs.readFileSync(s, { encoding: \"utf8\", flag: \"r\" });
const solcOutput = JSON.parse(rfs(\"out/$1.sol/$1.json\"));
const initcode = solcOutput[\"bytecode\"][\"object\"].slice(2);
const d = \"create2/$1\";
fs.writeFileSync(d + \"/initcode.txt\", initcode);
const t = solcOutput[\"metadata\"][\"settings\"][\"compilationTarget\"], k = Object.keys(t)[0];
fs.writeFileSync(d + \"/t\", k + \":\" + t[k]);
fs.writeFileSync(d + \"/initcodehash.txt\", require(\"@ethersproject/keccak256\").keccak256(\"0x\" + initcode));
" > "extract_$1.js";
# Run the js file.
node "extract_$1.js";
# Generate the standard json verification file.
forge verify-contract $(cast --address-zero) "$(<create2/$1/t)" --show-standard-json-input > "create2/$1/input.json";
# Remove the temporary files.
rm "create2/$1/t" > /dev/null 2>&1;
rm "extract_$1.js" > /dev/null 2>&1;
# Move the directory over to the actual deployment directory.
rm -rf "../create2/$1" > /dev/null 2>&1;
cp -r "create2/$1" "../create2/$1";
rm -rf "create2/$1" > /dev/null 2>&1;
}

# Generate the deployments.
generateDeployment "SuperMinter";
generateDeployment "SoundEditionV2";
generateDeployment "SoundCreatorV2";
generateDeployment "SoundOnChainMetadata";
generateDeployment "SoundMetadata";
Loading