Skip to content
This repository has been archived by the owner on Aug 5, 2024. It is now read-only.

Commit

Permalink
updated docs on the getting started page (#539)
Browse files Browse the repository at this point in the history
  • Loading branch information
GWSzeto authored Jul 29, 2024
1 parent a89859d commit 7de5df0
Showing 1 changed file with 188 additions and 179 deletions.
367 changes: 188 additions & 179 deletions src/app/contracts/modular-contracts/get-started/page.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DocImage, createMetadata, FeatureCard } from "@doc";
import { DocImage, createMetadata, FeatureCard, Steps, Step } from "@doc";

import deployCoreContract from './assets/deploy-core-contract.png';
import deploying from './assets/deploying.png';
Expand All @@ -22,202 +22,211 @@ export const metadata = createMetadata({
# Quickstart

#### Overview
Modular contracts are a composable set of contracts that can be combined to create a feature complete protocol. To learn more, refer to [How it works](https://thirdweb.com/contracts/modular-contracts/how-it-works)
Modular contracts are a composable set of contracts that can be combined to create a feature complete protocol. To learn more, refer to [How it works](https://portal.thirdweb.com/contracts/modular-contracts/how-it-works)

In this Quickstart, learn how to go over how to create an ERC-721 modular contract with fixed mint pricing

#### 1. Create a new forge project and install the modular-contracts package
Install Forge from this [guide](https://book.getfoundry.sh/getting-started/installation) from Foundry
```bash
forge init
forge install https://github.com/thirdweb-dev/modular-contracts.git
forge remappings > remappings.txt
```

#### 2. Create the core contract
In the `/src` folder, create a new file called `ERC721Start.sol` with the following code.
This will inherit the prebuilt `ERC721Core` contract. For a full list of prebuilt core contract, go [here]()
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {ERC721Core} from "modular-contracts/src/core/token/ERC721Core.sol";
contract ERC721Start is ERC721Core {
constructor(
string memory _name,
string memory _symbol,
string memory _contractURI,
address _owner
)
ERC721Core(
_name,
_symbol,
_contractURI,
_owner,
new address[](0),
new bytes[](0)
<Steps>
<Step title="Create a new forge project and install the modular-contracts package">
Install Forge from this [guide](https://book.getfoundry.sh/getting-started/installation) from Foundry
```bash
forge init
forge install https://github.com/thirdweb-dev/modular-contracts.git
forge remappings > remappings.txt
```
</Step>

<Step title="Create the core contract">
In the `/src` folder, create a new file called `ERC721Start.sol` with the following code.
This will inherit the prebuilt `ERC721Core` contract.
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {ERC721Core} from "modular-contracts/src/core/token/ERC721Core.sol";

contract ERC721Start is ERC721Core {
constructor(
string memory _name,
string memory _symbol,
string memory _contractURI,
address _owner
)
{}
}
```

#### 3. Deploy the core contract
In your terminal, run the following command
```bash
npx thirdweb deploy
```

Then select `ERC721Start`
After signing in, it should open up to the following page to deploy the `ERC721Start` contract
<DocImage src={deployCoreContract} />

After filling in the fields, select the Sepolia testnet chain and then hit Deploy

> If you need funds to deploy the contract, head over to the Sepolia faucet [here](https://thirdweb.com/sepolia/)
<DocImage src={deploying} />

After deploying the contract, you should be redirected to the deployed contract page
<DocImage src={deployedCoreContract} />

Hold onto this page as you will need it for later

#### 3. Create the extension contract
Back in your forge project, in the `/src` folder, create a file called `PricedExtension.sol` and paste in the following code.

For a better understanding of how extension contracts work, refer to the [starter template code](https://github.com/thirdweb-example/modular-contract-extension-starter/blob/main/src/ExtensionStarter.sol)
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {ModularExtension} from "modular-contracts/src/ModularExtension.sol";
import {BeforeMintCallbackERC721} from "modular-contracts/src/callback/BeforeMintCallbackERC721.sol";
contract PricedMint is ModularExtension, BeforeMintCallbackERC721 {
uint256 public constant mintPrice = 0.01 ether;
function getExtensionConfig()
external
pure
override
returns (ExtensionConfig memory config)
{
config.callbackFunctions = new CallbackFunction[](1);
config.callbackFunctions[0] = CallbackFunction(
this.beforeMintERC721.selector
);
config.requiredInterfaces = new bytes4[](1);
config.requiredInterfaces[0] = 0x80ac58cd; // ERC721.
ERC721Core(
_name,
_symbol,
_contractURI,
_owner,
new address[](0),
new bytes[](0)
)
{}
}
```
</Step>

function beforeMintERC721(
address _to,
uint256 _startTokenId,
uint256 _quantity,
bytes memory _data
) external payable virtual override returns (bytes memory) {
require(msg.value == mintPrice * _quantity, "Insufficient ETH sent");
}
}
```

#### 4. Publish the extension contract
In your terminal, run the following command
```
npx thirdweb publish
```
<Step title="Deploy the core contract">
In your terminal, run the following command
```bash
npx thirdweb deploy
```

Then select `PricedMint`
it should open up to the following page to publish the `PricedMint` contract
<DocImage src={publishExtensionContract} />
Then select `ERC721Start`
After signing in, it should open up to the following page to deploy the `ERC721Start` contract
<DocImage src={deployCoreContract} />

Accept the defaults and then hit "next"
It should then redirect you to choose which chain to deploy on.
Here we'll leave it on the Sepolia testnet
Afterwards, hit "Publish Contract"
<DocImage src={selectNetwork} />
After filling in the fields, select the Sepolia testnet chain and then hit Deploy

#### 5. Install the Extension onto the Core contract
Back to the deployed core contract page, then go and click on the "Manage" tab
<DocImage src={manageTabHighlight} />
> If you need funds to deploy the contract, head over to the Sepolia faucet [here](https://thirdweb.com/sepolia/)
It should then redirect to the edit extensions page
<DocImage src={installExtension} />
<DocImage src={deploying} />

Here, fill out the info as needed and then hit "Install"
After deploying the contract, you should be redirected to the deployed contract page
<DocImage src={deployedCoreContract} />

After it has finished installing, it should then show up under the "Installed Extension" section
<DocImage src={installedExtension} />
Hold onto this page as you will need it for later
</Step>

<Step title="Create the extension contract">
Back in your forge project, in the `/src` folder, create a file called `PricedExtension.sol` and paste in the following code.

#### 6. Test the modular contract
Now with the modular contract fully up and ready to go, we can test that it setup properly by running the following script
For a better understanding of how extension contracts work, refer to the [starter template code](https://github.com/thirdweb-example/modular-contract-extension-starter/blob/main/src/ExtensionStarter.sol)
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

```javascript
// Pre-requisite: install thirdweb <https://portal.thirdweb.com/typescript/v5>
import {ModularExtension} from "modular-contracts/src/ModularExtension.sol";
import {BeforeMintCallbackERC721} from "modular-contracts/src/callback/BeforeMintCallbackERC721.sol";

import {
createThirdwebClient,
getContract,
prepareContractCall,
sendTransaction,
waitForReceipt,
toUnits,
} from "thirdweb";
import { privateKeyToAccount } from "thirdweb/wallets";
import { sepolia } from "thirdweb/chains";
contract PricedMint is ModularExtension, BeforeMintCallbackERC721 {
uint256 public constant mintPrice = 0.01 ether;

const PRIVATE_KEY = "<"; // Paste your private key here
const SECRET_KEY = ""; // Paste your secret key here
function getExtensionConfig()
external
pure
override
returns (ExtensionConfig memory config)
{
config.callbackFunctions = new CallbackFunction[](1);

const TARGET_TOKEN_CORE_ADDRESS = ""; // Paste your target token core address here
const MINTER_RECIPIENT_ADDRESS = ""; // Paste your minter recipient address here

const client = createThirdwebClient({
secretKey: SECRET_KEY,
});
config.callbackFunctions[0] = CallbackFunction(
this.beforeMintERC721.selector
);

const account = privateKeyToAccount({
client,
privateKey: PRIVATE_KEY,
});

const contract = getContract({
client,
address: TARGET_TOKEN_CORE_ADDRESS,
chain: sepolia,
});
config.requiredInterfaces = new bytes4[](1);
config.requiredInterfaces[0] = 0x80ac58cd; // ERC721.
}

const transaction = prepareContractCall({
contract,
method: {
type: "function",
name: "mint",
inputs: [
{ name: "to", type: "address", internalType: "address" },
{ name: "amount", type: "uint256", internalType: "uint256" },
{ name: "data", type: "bytes", internalType: "bytes" },
],
value: toUnits("0.01", 18),
outputs: [],
stateMutability: "payable",
},
params: [MINTER_RECIPIENT_ADDRESS, 1, ""],
});

async function main() {
// Send transaction
const result = await sendTransaction({
transaction: transaction,
account: account,
});

const receipt = await waitForReceipt(result);

console.log("NFT minted tx: ", receipt.transactionHash);
}
function beforeMintERC721(
address _to,
uint256 _startTokenId,
uint256 _quantity,
bytes memory _data
) external payable virtual override returns (bytes memory) {
require(msg.value == mintPrice * _quantity, "Insufficient ETH sent");
}
}
```
</Step>

<Step title="Publish the extension contract">
In your terminal, run the following command
```
npx thirdweb publish
```

Then select `PricedMint`
it should open up to the following page to publish the `PricedMint` contract
<DocImage src={publishExtensionContract} />

Accept the defaults and then hit "next"
It should then redirect you to choose which chain to deploy on.
Here we'll leave it on the Sepolia testnet
Afterwards, hit "Publish Contract"
<DocImage src={selectNetwork} />
</Step>

<Step title="Install the Extension onto the Core contract">
Back to the deployed core contract page, then go and click on the "Manage" tab
<DocImage src={manageTabHighlight} />

It should then redirect to the edit extensions page
<DocImage src={installExtension} />

Here, fill out the info as needed and then hit "Install"

After it has finished installing, it should then show up under the "Installed Extension" section
<DocImage src={installedExtension} />
</Step>

<Step title="Test the modular contract">
Now with the modular contract fully up and ready to go, we can test that it setup properly by running the following script

```javascript
// Pre-requisite: install thirdweb <https://portal.thirdweb.com/typescript/v5>

import {
createThirdwebClient,
getContract,
prepareContractCall,
sendTransaction,
waitForReceipt,
toUnits,
} from "thirdweb";
import { privateKeyToAccount } from "thirdweb/wallets";
import { sepolia } from "thirdweb/chains";

const PRIVATE_KEY = "<"; // Paste your private key here
const SECRET_KEY = ""; // Paste your secret key here

const TARGET_TOKEN_CORE_ADDRESS = ""; // Paste your target token core address here
const MINTER_RECIPIENT_ADDRESS = ""; // Paste your minter recipient address here

const client = createThirdwebClient({
secretKey: SECRET_KEY,
});

const account = privateKeyToAccount({
client,
privateKey: PRIVATE_KEY,
});

const contract = getContract({
client,
address: TARGET_TOKEN_CORE_ADDRESS,
chain: sepolia,
});

const transaction = prepareContractCall({
contract,
method: {
type: "function",
name: "mint",
inputs: [
{ name: "to", type: "address", internalType: "address" },
{ name: "amount", type: "uint256", internalType: "uint256" },
{ name: "data", type: "bytes", internalType: "bytes" },
],
value: toUnits("0.01", 18),
outputs: [],
stateMutability: "payable",
},
params: [MINTER_RECIPIENT_ADDRESS, 1, ""],
});

async function main() {
// Send transaction
const result = await sendTransaction({
transaction: transaction,
account: account,
});

const receipt = await waitForReceipt(result);

console.log("NFT minted tx: ", receipt.transactionHash);
}

main()
main()
```
</Step>
</Steps>

0 comments on commit 7de5df0

Please sign in to comment.