# ZORA Docs ## API Access There are a few supported APIs to access ZORA chain information. 1. RPC Access: * Use viem/ethers with the public RPC url ([https://rpc.zora.energy/](https://rpc.zora.energy/)) or [your own node](https://docs.conduit.xyz/guides/run-a-node/op-stack-node) to access information. * You can create a [conduit account](https://docs.conduit.xyz/nodes/get-api-keys) to get a free API key for the ZORA network without rate limits on the public node. * You can also use [dRPC](https://drpc.org/chainlist/zora) or [QuickNode](https://www.quicknode.com/chains/zora) as paid RPC node providers. * If you're looking for dedicated infrastructure, check out QuickNode's [Clusters](https://www.quicknode.com/clusters) offering. 2. Explorer Access: Use blockscout APIs to access data: * [rest endpoint](https://explorer.zora.energy/api-docs) / [docs](https://docs.blockscout.com/for-users/api/rest-api-endpoints) * [graphql endpoint](https://explorer.zora.energy/graphiql) / [docs](https://docs.blockscout.com/for-users/api/graphql) * [rest / etherscan type api endpoint](https://explorer.zora.energy/api) / [docs](https://docs.blockscout.com/for-users/api/rpc-endpoints) ## Bridging ### Bridging User Interfaces The official bridge for a native bridge can be found at [https://bridge.zora.energy/](https://bridge.zora.energy/). To bridge ERC-20s, the optimism superbridge.app supports ZORA: [https://superbridge.app/zora](https://superbridge.app/zora). For instant bridging, multiple providers allow for instant bridging both from and to the ZORA network. ### Bridging Technical Details #### ETH => Zora Network ETH can be bridged from Ethereum (L1) to the Zora Network (L2) by calling `depositTransaction` on the L1 contract address below. It will take about **1-2 minutes** for funds to show up on the Zora Network. You must also set the gas limit to **60,000**. The ETH must also be set as the `value` in the overrides of the transaction. ``` depositTransaction( address _to, // Target address on L2. uint256 _value, // ETH value to send to the recipient. uint64 _gasLimit, // Minimum L2 gas limit (can be greater than or equal to this value). bool _isCreation, // Whether or not the transaction is a contract creation. bytes __data // Data to trigger the recipient with. ) ``` \*\* Warning: \*\* Please do not transfer large amounts of ETH to Layer 2. It is recommended to transfer a small amount of ETH when bridging for the first time. Lastly, **DO NOT** transfer WETH or any ERC-20 tokens to the bridge address. * Zora Network Mainnet: [0x1a0ad011913A150f69f6A19DF447A0CfD9551054](https://etherscan.io/address/0x1a0ad011913A150f69f6A19DF447A0CfD9551054) * Zora Network Goerli: [0xDb9F51790365e7dc196e7D072728df39Be958ACe](https://goerli.etherscan.io/address/0xDb9F51790365e7dc196e7D072728df39Be958ACe) ## Deploying Contracts Deploying contracts can be done with familiar EVM tools like [Hardhat](https://hardhat.org/) and [Foundry](https://book.getfoundry.sh/). Make sure to configure these tools with the correct chain ID and RPC URL to deploy smart contracts to Zora Network Goerli and Zora Network Mainnet. See the [Network](/zora-network/network) section for more information. ### Foundry #### Setup See the [Foundry](https://book.getfoundry.sh/) documentation to initialize your project with Foundry. #### Deploying To deploy smart contracts to Zora Network with Foundry, remember to use the --rpc-url and --chain-id flags with the correct values for the Zora network you are deploying to. For example, to deploy to Zora Goerli: ```bash forge create src/MyContract.sol:MyContract --chain-id 999 --rpc-url https://testnet.rpc.zora.energy/ --private-key $PRIVATE_KEY ``` You can use the same flags for more complicated deploy commands, such as with constructor arguments or a deploy script. #### Verifying To deploy and verify your contract in one command, use Foundry's verification flags configured with Blockscout and Zora Network's Blockscout API: ```bash forge create src/MyContract.sol:MyContract --chain-id 999 --rpc-url https://testnet.rpc.zora.energy/ --private-key $PRIVATE_KEY --verify --verifier blockscout --verifier-url https://testnet.explorer.zora.energy/api\? ``` You can also verify a pre-existing contract with the `forge verify-contract` command using the same flags (`--verifier` and `--verifier-url`). Note: Zora uses Blockscout which requires appending `\?` to the end of the API url like in the example above. More details [here](https://github.com/foundry-rs/foundry/issues/5160). Alternatively, use Standard JSON Input to verify a pre-existing contract by appending the `--show-standard-json-input` option to `forge verify-contract`, creating a JSON file from the output and uploading that file to the Blockscout UI. ### Hardhat #### Setup Refer to Hardhat's [Quick Start](https://hardhat.org/hardhat-runner/docs/getting-started#quick-start) guide to install Hardhat and initialize your project. To configure your project, add the Zora Network information in `hardhat.config.js`: ```js import { HardhatUserConfig } from 'hardhat/config'; import '@nomicfoundation/hardhat-toolbox'; require('dotenv').config(); const config: HardhatUserConfig = { solidity: { version: '0.8.17', }, networks: { // for testnet 'zora-goerli': { url: 'https://testnet.rpc.zora.energy/', accounts: [process.env.WALLET_KEY as string], }, // for mainnet 'zora-mainnet': { url: 'https://rpc.zora.energy/', accounts: [process.env.WALLET_KEY as string], }, }, defaultNetwork: 'hardhat', }; export default config; ``` #### Deploying Once you've configured your Hardhat project to work with Zora Network, you can proceed with the Hardhat guide to compile, test, and deploy your contracts. #### Verifying Zora Network uses Blockscout for chain exploration and contract verification. See Blockscout's [Hardhat plugin guide](https://docs.blockscout.com/for-users/verifying-a-smart-contract/hardhat-verification-plugin) to verify contracts with Hardhat and Blockscout. ### Tenderly [Tenderly](https://tenderly.co?mtm_campaign=ext-docs\&mtm_kwd=zora) is a full-stack Web3 development infrastructure that helps developers build, stage, test, and monitor decentralized applications. It provides Virtual TestNets for staging and testing in mainnet-like environments, debugging and simulation tools for transaction analysis, and real-time monitoring capabilities. Use Tenderly [**Virtual TestNets**]() to streamline user onboarding on Zora. Create hands-on onboarding experiences in a dedicated **staging environment**. With Tenderly, you can: * Deploy contracts on [Virtual TestNets](https://docs.tenderly.co/virtual-testnets?mtm_campaign=ext-docs\&mtm_kwd=zora) and stage them in a mainnet-like environment for the rest of your team * Build [CI/CD pipelines](https://docs.tenderly.co/virtual-testnets/ci-cd/github-actions-foundry?mtm_campaign=ext-docs\&mtm_kwd=zora) for smart contracts using Github Actions * Fix bugs and test changes in a safe environment using [Tenderly Debugger](https://docs.tenderly.co/debugger?mtm_campaign=ext-docs\&mtm_kwd=zora) * Monitor and analyze transactions with \[Developer Explorer][https://docs.tenderly.co/developer-explorer?mtm\_campaign=ext-docs\&mtm\_kwd=zora](https://docs.tenderly.co/developer-explorer?mtm_campaign=ext-docs\&mtm_kwd=zora)) * [Verify contracts](https://docs.tenderly.co/contract-verification?mtm_campaign=ext-docs\&mtm_kwd=zora) on mainnet in public and private mode #### Foundry deployment and verification To deploy a contract to a Virtual TestNet with Foundry, use the `--rpc-url` flag with the Virtual TestNet RPC URL and the `--etherscan-api-key` flag with your Tenderly access token. For example, to deploy and verify a Counter contract to a Virtual TestNet froom Foundry run the following command: ```bash forge create Counter \ --rpc-url $TENDERLY_VIRTUAL_TESTNET_RPC_URL \ --etherscan-api-key $TENDERLY_ACCESS_TOKEN \ --private-key $PRIVATE_KEY \ --verify \ --verifier-url $TENDERLY_VIRTUAL_TESTNET_RPC_URL/verify/etherscan ``` #### Hardhat deployment and verification To [deploy and verify contracts](https://docs.tenderly.co/contract-verification/hardhat?mtm_campaign=ext-docs\&mtm_kwd=zora) to a Virtual TestNet from Hardhat add the following configuration to `hardhat.config.ts` and proceed with deployment as usual. ```ts import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; import * as tdly from "@tenderly/hardhat-tenderly"; const config: HardhatUserConfig = { solidity: "0.8.19", networks: { tenderly_zora_virtual_testnet: { // your Tenderly TestNet RPC url: "https://virtual.zora.rpc.tenderly.co/872ac073-...", chainId: 735717777777 } }, tenderly: { username: "Your account slug", project: "Your project slug", // Mainnet contract verification visible only in Tenderly. // Omitting or setting to `false` makes it visible to the whole world. // Alternatively, configure verification visibility using // an environment variable `TENDERLY_PUBLIC_VERIFICATION`. privateVerification: process.env.TENDERLY_PUBLIC_VERIFICATION !== 'true', }, etherscan: { apiKey: "YOUR_TENDERLY_API_KEY", customChains: [ { network: "tenderly_zora_virtual_testnet", chainId: 735717777777, urls: { apiURL: `https://virtual.zora.rpc.tenderly.co/872ac073-.../verify/etherscan`, browserURL: "https://virtual.zora.rpc.tenderly.co/872ac073-..." } } ] }, }; export default config; ``` #### CI/CD with Github Actions ## Deployed Contracts ### Zora Mainnet #### Seaport 1.5 | Name | Address | Standard | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | | ConduitController | [0x00000000F9490004C11Cef243f5400493c00Ad63](https://explorer.zora.energy/address/0x00000000F9490004C11Cef243f5400493c00Ad63) | yes | | Seaport 1.5 | [0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC](https://explorer.zora.energy/address/0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC) | yes | | Keyless Create2 | [0x7A0D94F55792C434d74a40883C6ed8545E406D12](https://explorer.zora.energy/address/0x7A0D94F55792C434d74a40883C6ed8545E406D12) | yes | | Immutable Create2 Factory | [0x0000000000ffe8b47b3e2130213b802212439497](https://explorer.zora.energy/address/0x0000000000ffe8b47b3e2130213b802212439497) | yes | #### Gnosis Safe (L2) | Name | Address | Standard | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | | CompatibilityFallbackHandler | [0xf48f2B2d2a534e402487b3ee7C18c33Aec0Fe5e4](https://explorer.zora.energy/address/0xf48f2B2d2a534e402487b3ee7C18c33Aec0Fe5e4) | yes | | CreateCall | [0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4](https://explorer.zora.energy/address/0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4) | yes | | GnosisSafe | [0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552](https://explorer.zora.energy/address/0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552) | yes | | GnosisSafeL2 | [0x3E5c63644E683549055b9Be8653de26E0B4CD36E](https://explorer.zora.energy/address/0x3E5c63644E683549055b9Be8653de26E0B4CD36E) | yes | | MultiSend | [0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761](https://explorer.zora.energy/address/0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761) | yes | | MultiSendCallOnly | [0x40A2aCCbd92BCA938b02010E17A5b8929b49130D](https://explorer.zora.energy/address/0x40A2aCCbd92BCA938b02010E17A5b8929b49130D) | yes | | ProxyFactory | [0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2](https://explorer.zora.energy/address/0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2) | yes | | SignMessageLib | [0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2](https://explorer.zora.energy/address/0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2) | yes | | SimulateTxAccessor | [0x59AD6735bCd8152B84860Cb256dD9e96b85F69Da](https://explorer.zora.energy/address/0x59AD6735bCd8152B84860Cb256dD9e96b85F69Da) | yes | #### Utilities Zora Network Goerli is a Testnet L2 built on top of the Goerli Testnet. The crypto on this network has no value and is meant for testing purposes. | Name | Value | Standard | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | | Immutable Create2 Factory | [0x0000000000ffe8b47b3e2130213b802212439497](https://explorer.zora.energy/address/0x0000000000ffe8b47b3e2130213b802212439497) | yes | | JsonExtensionRegistry | [0xABCDEFEd93200601e1dFe26D6644758801D732E8](https://explorer.zora.energy/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | yes | | Multicall3 | [0xcA11bde05977b3631167028862bE2a173976CA11](https://explorer.zora.energy/address/0xcA11bde05977b3631167028862bE2a173976CA11) | yes | #### ZORA NFTs | Name | Contract | Value | Standard | | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | | ZORA ERC 721 Factory | ZoraNFTCreatorProxy | [0xA2c2A96A232113Dd4993E8b048EEbc3371AE8d85](https://explorer.zora.energy/address/0xA2c2A96A232113Dd4993E8b048EEbc3371AE8d85) | yes | | ZORA ERC 721 | All contracts | [Github](https://github.com/ourzora/zora-drops-contracts/blob/main/addresses/7777777.json) | no | | ZORA ERC 1155 Factory | ZoraCreator1155Factory | [0x35ca784918bf11692708c1D530691704AAcEA95E](https://explorer.zora.energy/address/0x35ca784918bf11692708c1D530691704AAcEA95E) | no | | ZORA ERC 1155 | All contracts | [Github](https://github.com/ourzora/zora-protocol/blob/main/packages/erc20z/addresses/7777777.json) | no | ## Ethereum vs Zora Network Zora Network harnesses the Bedrock release of the [OP Stack](https://stack.optimism.io/), which is purposely structured to mimic Ethereum as closely as possible. Still, there exist slight differences in the behavior of the Zora Network compared to Ethereum. When building applications on the Zora Network, these nuances should be noted: * New blocks are created every 2 seconds on the Zora Network. * The gas limit for a Zora Network block is 30,000,000. * [OP Codes](https://stack.optimism.io/docs/releases/bedrock/differences/#opcode-differences) * [RPC API](https://stack.optimism.io/docs/releases/bedrock/differences/#network-specifications) * [Tx Costs](https://stack.optimism.io/docs/releases/bedrock/differences/#transaction-costs) ## Introduction ##### Imagination Onchain The Zora Network is a fast, cost-efficient, and scalable Layer 2 built to help bring media onchain. Many L2s are currently DeFi centric whereas the Zora Network is an ecosystem that puts NFTs first. * Transactions confirm in seconds * Minting an NFT costs less than $0.50 * Opens up new possibilities onchain Secured by Ethereum, Powered by the [OP Stack](https://stack.optimism.io/). Although Zora deployed the Zora Network software, Zora does not operate the Zora Network itself. ## Connecting MetaMask #### Adding to MetaMask Addresses in your MetaMask will work and be the same on both Ethereum and the Zora Network. However, to submit transactions to the Zora Network you must add the network to your wallet. * First, open the MetaMask desktop extension * Click on where it says **Ethereum Mainnet** at the top and click **Add Network** metamask-network
* This will open a new window, then click **Add a new network manually** at the bottom metamask-network
* Lastly, add in the configuration details listed in the network section [here](./network). Once saved, you will then be able to submit transactions on the Zora Network. metamask-network ## Network Details #### Zora Network Mainnet Zora Network is an L2 built on top of Ethereum using the [OP stack](https://stack.optimism.io/). | Name | Value | | -------------- | ------------------------------------------------------------ | | Network | Zora | | Chain ID | 7777777 | | Gas Token | ETH | | RPC | [https://rpc.zora.energy](https://rpc.zora.energy) | | Websocket | wss\://rpc.zora.energy | | Block Explorer | [https://explorer.zora.energy](https://explorer.zora.energy) | To get a non-rate-limited API key for the zora RPC, sign up for an account at [Conduit.xyz](https://conduit.xyz/rpc-keys) for an RPC API key. #### Zora Network Sepolia Testnet Zora Sepolia Network is an Testnet L2 built on top of Ethereum Sepolia using the [OP stack](https://stack.optimism.io/). | Name | Value | | -------------- | ---------------------------------------------------------------------------- | | Network | Sepolia | | Chain ID | 999999999 | | Gas Token | ETH | | RPC | [https://sepolia.rpc.zora.energy](https://sepolia.rpc.zora.energy) | | Websocket | wss\://sepolia.rpc.zora.energy | | Block Explorer | [https://sepolia.explorer.zora.energy](https://sepolia.explorer.zora.energy) | *** ### Contract Addresses ##### Zora Network Mainnet | Name | Address | | ------------------------------------ | ------------------------------------------ | | OptimismPortalProxy | 0x1a0ad011913A150f69f6A19DF447A0CfD9551054 | | OptimismPortal | 0x43260ee547c3965bb2a0174763bb8FEcC650BA4A | | SystemConfigProxy | 0xA3cAB0126d5F504B071b81a3e8A2BBBF17930d86 | | L1ERC721Bridge | 0xDBCdA21518AF39E7feb9748F6718D3db11591461 | | SystemDictator | 0x2E44e62992f14b904Bfefd93e63D98D7dA4fcD66 | | PortalSender | 0xd6C5Df0a29562521b2B26fAc218e3dAf0a4dFC9B | | L1StandardBridge | 0xbF6acaF315477b15D638bf4d91eA48FA79b58335 | | Lib\_AddressManager | 0xEF8115F2733fb2033a7c756402Fc1deaa56550Ef | | L2OutputOracleProxy | 0x9E6204F750cD866b299594e2aC9eA824E2e5f95c | | OptimismMintableERC20FactoryProxy | 0xc52BC7344e24e39dF1bf026fe05C4e6E23CfBcFf | | Proxy\_\_OVM\_L1StandardBridge | 0x3e2Ea9B92B7E48A52296fD261dc26fd995284631 | | ProxyAdmin | 0xD4ef175B9e72cAEe9f1fe7660a6Ec19009903b49 | | OptimismMintableERC20Factory | 0x84ee4b9673598ca2FbDad4Ba4a27A58D6328Ec46 | | Proxy\_\_OVM\_L1CrossDomainMessenger | 0xdC40a14d9abd6F410226f1E6de71aE03441ca506 | | L1ERC721BridgeProxy | 0x83A4521A3573Ca87f3a971B169C5A0E1d34481c3 | | SystemConfig | 0x17fb7c8Ce213F1A7691ee41EA880ABf6eBC6fa95 | | L1CrossDomainMessenger | 0x363B4B1ADa52E50353f746999bd9E94395190d2C | | L2OutputOracle | 0x89336159Edd615260a95309e46343602D6b6489e | | SystemDictatorProxy | 0x50bA02c0Ca5E7bF772913EaF24Fb1fd3842a5f19 | ##### Zora Network Sepolia | Name | Address | | ------------------------------------ | ------------------------------------------ | | L1ERC721Bridge | 0xDBCdA21518AF39E7feb9748F6718D3db11591461 | | SystemDictator | 0x2E44e62992f14b904Bfefd93e63D98D7dA4fcD66 | | PortalSender | 0xd6C5Df0a29562521b2B26fAc218e3dAf0a4dFC9B | | L1StandardBridge | 0xbF6acaF315477b15D638bf4d91eA48FA79b58335 | | Lib\_AddressManager | 0xEF8115F2733fb2033a7c756402Fc1deaa56550Ef | | L2OutputOracleProxy | 0x9E6204F750cD866b299594e2aC9eA824E2e5f95c | | OptimismMintableERC20FactoryProxy | 0xc52BC7344e24e39dF1bf026fe05C4e6E23CfBcFf | | Proxy\_\_OVM\_L1StandardBridge | 0x3e2Ea9B92B7E48A52296fD261dc26fd995284631 | | ProxyAdmin | 0xD4ef175B9e72cAEe9f1fe7660a6Ec19009903b49 | | OptimismMintableERC20Factory | 0x84ee4b9673598ca2FbDad4Ba4a27A58D6328Ec46 | | OptimismPortal | 0x43260ee547c3965bb2a0174763bb8FEcC650BA4A | | Proxy\_\_OVM\_L1CrossDomainMessenger | 0xdC40a14d9abd6F410226f1E6de71aE03441ca506 | | L1ERC721BridgeProxy | 0x83A4521A3573Ca87f3a971B169C5A0E1d34481c3 | | SystemConfig | 0x17fb7c8Ce213F1A7691ee41EA880ABf6eBC6fa95 | | OptimismPortalProxy | 0x1a0ad011913A150f69f6A19DF447A0CfD9551054 | | L1CrossDomainMessenger | 0x363B4B1ADa52E50353f746999bd9E94395190d2C | | L2OutputOracle | 0x89336159Edd615260a95309e46343602D6b6489e | | SystemDictatorProxy | 0x50bA02c0Ca5E7bF772913EaF24Fb1fd3842a5f19 | | SystemConfigProxy | 0xA3cAB0126d5F504B071b81a3e8A2BBBF17930d86 | ## Zora NFT Protocol SDKs The Zora NFT Protocol SDKs are a suite of typescript libraries and utilities that simplify interacting with the Zora protocol contracts. ### Protocol Deployments Package The [Protocol Deployments](/protocol-sdk/protocol-deployments) package provides contract ABIs, deployed addresses, and typescript types for the Zora Contracts. These bundled configs and ABIs can be used in conjunction with wagmi or viem to interact with the Zora contracts in typescript without needing to write any solidity. ```ts twoslash import { protocolRewardsABI, zoraCreator1155FactoryImplABI, protocolRewardsAddress, zoraCreator1155FactoryImplAddress, } from "@zoralabs/protocol-deployments"; ``` ### Protocol SDK The Protocol SDK is a typescript package that simplifies interacting with the Zora protocol by generating required transactions for our contracts. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/config.ts] // @filename: example.ts // ---cut--- import { publicClient, chain } from './config'; import { createCollectorClient } from "@zoralabs/protocol-sdk"; const tokenContract = "0x1234567890123456789012345678901234567890"; const tokenId = 1n; const mintToAddress = "0x71907e8Ae7aeFb58ceC8eb46DAf4fc78c29E5173"; const quantityToMint = 1; const minterAccount = "0xCb8454D64AFeB46455cB4847C53279F6cdCbFb5e"; const collectorClient = createCollectorClient({ chainId: chain.id, publicClient }); // prepare a transaction to mint an 1155 token const { parameters } = await collectorClient.mint({ mintType: "1155", // 1155 contract address tokenContract, // id of the token to mint tokenId, // address that will receive the minted tokens mintRecipient: mintToAddress, // quantity of tokens to mint quantityToMint, // account to execute the mint transaction minterAccount, }); // simulate the transaction const { request } = await publicClient.simulateContract(parameters); ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/config.ts] ``` ::: #### Installation To add `@zoralabs/protocol-sdk` to your project, install the required packages: :::code-group ```bash [pnpm] pnpm add @zoralabs/protocol-sdk viem@2.x ``` ```bash [npm] npm install @zoralabs/protocol-sdk viem@2.x ``` ```bash [yarn] yarn add @zoralabs/protocol-sdk viem@2.x ``` ::: If using wagmi install `@tanstack/react-query` as well: ```bash npm install @zoralabs/protocol-sdk viem@2.x @tanstack/react-query ``` #### Usage The Zora Protocol SDK contains both a Creator Client and a Collector Client. The Creator Client is used to create and manage Zora creator 1155 contracts and tokens, while the Collector Client is used to mint Zora creator 1155, 721, and premints. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/config.ts] // @filename: example.ts // ---cut--- import { publicClient, chain } from './config'; import { createCreatorClient, createCollectorClient } from "@zoralabs/protocol-sdk"; const creatorClient = createCreatorClient({ chainId: chain.id, publicClient }); // @noErrors creatorClient. // ^| const collectorClient = createCollectorClient({ chainId: chain.id, publicClient }); // @noErrors collectorClient. // ^| ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/config.ts] ``` ::: ## Protocol Deployments Package `@zoralabs/protocol-deployments` is a typescript package that provides contract ABIs, deployed addresses, and typescript types for the Zora contracts. These bundled configs and ABIs can be used in conjunction with wagmi or viem to interact with the Zora contracts in typescript. #### Installation To add `@zoralabs/protocol-deployments` to your project, install the required package: :::code-group ```bash [pnpm] pnpm add @zoralabs/protocol-deployments ``` ```bash [npm] npm install @zoralabs/protocol-deployments ``` ```bash [yarn] yarn add @zoralabs/protocol-deployments ``` ::: #### Importing Contract ABIs The package exports a set of contract ABIs for the Zora Protocol. These can be imported and used as follows: ```ts twoslash import { protocolRewardsABI, zoraCreator1155FactoryImplABI, } from "@zoralabs/protocol-deployments"; ``` #### Importing Contract Addresses The package exports addresses each Zora contract is deployed to on each chain. ```ts twoslash import { protocolRewardsAddress, zoraCreator1155FactoryImplAddress, } from "@zoralabs/protocol-deployments"; import { zora } from "viem/chains"; // get addresses contracts are deployed on the Zora chain const protocolRewardsAddressOnZora = protocolRewardsAddress[zora.id]; const zoraCreator1155FactoryImplAddressOnZora = zoraCreator1155FactoryImplAddress[zora.id]; ``` #### Usage with React wagmi Hooks The bundled contract ABIs and addresses can be used in conjunction with [wagmi](https://wagmi.sh/) to interact with contracts in a typesafe manner in React Apps with minimal code. First, install `@tanstack/react-query` with `@zoralabs/protocol-deployments`: :::code-group ```bash [pnpm] pnpm add @zoralabs/protocol-deployments @tanstack/react-query ``` ```bash [npm] npm install @zoralabs/protocol-deployments @tanstack/react-query ``` ```bash [yarn] yarn add @zoralabs/protocol-deployments @tanstack/react-query ``` ::: wagmi hooks like [useReadContract](https://wagmi.sh/react/api/hooks/useReadContract) and [useWriteContract](https://wagmi.sh/react/api/hooks/useWriteContract) can be used in conjunction with the contract ABIs and addresses: ```tsx twoslash [index.tsx] // [!include ~/snippets/protocol-deployments/wagmi/protocolRewards.tsx] ``` #### Usage with viem The bundled contract ABIs and addresses can be used in conjunction with [viem](https://viem.sh/) to interact with contracts in a typesafe manner with minimal code: :::code-group ```ts twoslash [index.tsx] // @filename: config.ts // [!include ~/snippets/protocol-deployments/viem/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-deployments/viem/protocolRewards.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-deployments/viem/config.ts] ``` ::: ## Building Contract Metadata Zora 1155 and 721 contracts have contract-wide json metadata containing descriptive info about the contract, including a name and image. This json metadata is pinned to [IPFS](https://ipfs.tech/). The structure of Contract Metadata is defined in a type exported from the SDK, ContractMetadataJson: ```ts type ContractMetadataJson = { name?: string; description?: string; image?: string; } ``` The `image` field should point to an image file pinned to ipfs. The Zora Protocol SDK exports a type `ContractMetadataJson` that defines this json structure. Here's some example code for building contract metadata json: :::code-group ```ts twoslash [example.ts] // @filename: pinata.ts // [!include ~/snippets/protocol-sdk/ipfs/pinata.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/ipfs/contractpinata.ts] ``` ```ts twoslash [pinata.ts] // [!include ~/snippets/protocol-sdk/ipfs/pinata.ts] ``` ::: ## Building Token Metadata Each token in a Zora 1155 or 721 contract has a metadata uri field which points to a JSON Metadata file, pinned to [IPFS](https://ipfs.tech/), containing information about the media associated with the token as well as additional descriptive info. The Zora Protocol SDK provides some utility methods to help build the JSON metadata needed for tokens. It does not provide an endpoint for pinning the JSON metadata to IPFS. This guide will show how to use the SDK to build the metadata and pin it to IPFS using your preferred IPFS pinning method. The general structure of Token Metadata is defined in a type exported from the SDK, `TokenMetadataJson`: ```ts twoslash type TokenMetadataJson = { name: string; description?: string; /** Primary image file */ image?: string; animation_url?: string | null; content?: { mime: string; uri: string; } | null; attributes?: { trait_type: string; value: string; }; }; ``` ### Building Token Metadata using SDK helper methods The Zora Protocol SDK provides a utility to build JSON metadata for a token with the helper method `makeMediaTokenMetadata()`. Note that the media must be pinned to IPFS outside of this function call. Once the token metadata is generated by this function, it must be pinned to IPFS. The Zora Protocol SDK doesn't provide a pinning service, but this example will show how to pin the necessary assets and corresponding json metadata using [Pinata](https://docs.pinata.cloud/pinning/pinning-files) :::code-group ```ts twoslash [example.ts] // @filename: pinata.ts // [!include ~/snippets/protocol-sdk/ipfs/pinata.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/ipfs/imagepinata.ts] ``` ```ts twoslash [pinata.ts] // [!include ~/snippets/protocol-sdk/ipfs/pinata.ts] ``` ::: ### Building Metadata for Text NFTs Zora Text NFTs have text for the token media, and look like the following: ```json { "name": "My Text NFT", "content": { "mime": "text/plain", "uri": "{text file url}" }, "image": "{text preview thumbnail image url}", "animation_url": "{text file url}" } ``` The Zora Protocol SDK provides helper methods to create the files and build the metadata json needed for text NFTs. The function `generateTextNftMetadataFiles()` takes in a string for the `text`, and returns a `name`, `mediaUrlFile` which is a `.txt` file containing the text, and a `thumbnailUrl` which is a generated thumbnail image file with part of the text drawn into it. ```ts twoslash import { generateTextNftMetadataFiles} from '@zoralabs/protocol-sdk'; const { name, mediaUrlFile, thumbnailFile } = await generateTextNftMetadataFiles("Hello, World!"); ``` Once the files are generated, they must be pinned to IPFS gateway. With the ipfs urls of those files, the final metadata json can be built and pinned to IPFS. Here's an example using the [Pinata](https://docs.pinata.cloud/pinning/pinning-files) as an IPFS pinning service: :::code-group ```ts twoslash [example.ts] // @filename: pinata.ts // [!include ~/snippets/protocol-sdk/ipfs/pinata.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/ipfs/textpinata.ts] ``` ```ts twoslash [pinata.ts] // [!include ~/snippets/protocol-sdk/ipfs/pinata.ts] ``` ::: ## Creating an 1155 that can be minted in ERC-20 tokens 1155s can be priced and minted using an ERC-20 token. To create an 1155 token that is priced in ERC-20: * `token.salesConfig.type` must be set to `erc20Mint` * `token.salesConfig.currency` must be set to the address of the ERC20 token. * `token.salesConfig.pricePerToken` argument is set to the amount of ERC-20 tokens required to mint each token: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: data.ts // [!include ~/snippets/protocol-sdk/create/data.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNew1155WithErc20Mint.ts] ``` ```ts twoslash [data.ts] // [!include ~/snippets/protocol-sdk/create/data.ts] ``` ```ts twoslash [config.ts] filename="config.ts" // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ## getRewardsBalances The `getRewardsBalances` function on the `creatorClient` allows you to view the rewards and royalties balances for any account. This function returns two types of balances: 1. Protocol Rewards: The total rewards balance from primary sales, stored in the Protocol Rewards contract. 2. Royalties: The total royalties earned from [onchain secondary sales.]() The royalties balances are aggregated by ERC20 token and also include the sum for ETH. This provides a comprehensive view of an account's earnings from both primary and secondary sales. ### Usage :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/getRewardsBalances.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ### Returns `{ protocolRewards: bigint, royalties: Record }` #### protocolRewards * **Type:** `bigint` The total rewards balance from the Protocol Rewards contract. #### royalties * **Type:** `Record` The total royalties balances from secondary sales, aggregated by ERC20 token and summed up for eth. ### Parameters #### account * **Type:** `Address` | `Account` The account to get the rewards balances for. ## Create Onchain 1155 Contracts & Tokens The Protocol SDK can be used to prepare transactions to create 1155 contracts and tokens, using the Creator Client. ### Setup/Create a Public Client Initialize or get a `PublicClient` using viem or wagmi. The chain id of the public client is used to determine the network to interact with. :::code-group ```ts twoslash [viem.ts] import { createPublicClient, http, Chain } from 'viem'; import { zora } from "viem/chains"; const publicClient = createPublicClient({ chain: zora as Chain, transport: http() }); ``` ```ts twoslash [react.tsx] import { usePublicClient } from "wagmi"; const publicClient = usePublicClient(); ``` ::: ### Creating a new 1155 contract and token with Secondary Markets The function `create1155` is used to create a new 1155 contract and token. By default, the token will be created with the [ZoraTimedSaleStrategyMinter](https://github.com/ourzora/zora-protocol/blob/main/packages/erc20z/src/minter/ZoraTimedSaleStrategyImpl.sol) as the minter, meaning that after the primary sale is complete, [a secondary market powered by Uniswap will begin.](https://support.zora.co/en/articles/2519873) The `contract` argument needs to be contract creation parameters. Calling this function prepares a parameters for a transaction that creates an 1155 contract at the deterministic address based on those parameters, and a token on that contract. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNew1155ContractOrToken.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: #### Custom parameters for secondary markets The following snippet shows the parameters for customizing the settings for the secondary market. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNew1155ContractOrTokenWithCustomParams.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: With the update to use the v2 sales config it introduces `marketCountdown` and `minimumMarketEth` in version 0.9.5 of the sdk. ### Configuring the backing ERC20 Token Name and Symbol for the 1155 Secondary Market When leveraging the [secondary markets](https://support.zora.co/en/articles/2519873) feature, a backing ERC20 token is created with a name and symbol for each minted 1155.\ By default, the name is copied from the contract name, and the symbol is generated by converting the name into a 4 character symbol.\ Alternatively these can be manually set by configuring the `token.salesConfig.erc20Name` and `token.salesConfig.erc20Symbol` properties correspondingly: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNew1155TokenErc20zName.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ### Creating a token on an existing 1155 contract To create a token on an existing 1155 contract, the function `create1155OnExistingContract` must be called with the 1155 contract address and the token creation parameters. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: createNewContract.ts // [!include ~/snippets/protocol-sdk/create/createNewContract.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNew1155Token.ts] ``` ```ts twoslash [createNewContract.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: createNewContract.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNewContract.ts] ``` ```ts twoslash [config.ts] filename="config.ts" // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ### Setting a price per token A price per token can be optionally set to earn additional ETH on the primary sale when each token is minted, by setting `token.salesConfig.pricePerToken`.\ If the `pricePerToken` is set to more than 0, there will be no `creatorReward` earned on the mint fee. If a pricePerToken is set to more than 0, then the token is setup with the [ZoraCreatorFixedPriceSaleStrategy](https://github.com/ourzora/zora-protocol/blob/main/packages/1155-contracts/src/minters/fixed-price/ZoraCreatorFixedPriceSaleStrategy.sol) as its minter. This will also result in not being able to [leverage the onchain secondary market feature](https://support.zora.co/en/articles/2519873) for tokens minted using this minter. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNew1155WithPrice.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ### Minting a token after creating Sometimes it is desired to be able to mint a token right after creating one. This can be done with the function `prepareMint` that is returned from the creation functions. This function will prepare a transaction to mint a token on the token and/or contract that was created. Note that this transaction can only be executed after the token has been created onchain. :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: createNewContract.ts // [!include ~/snippets/protocol-sdk/create/createNewContract.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/mintFromCreate.ts] ``` ```ts twoslash [createNewContract.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: createNewContract.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/createNewContract.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: import {Callout} from 'vocs/components' Premint is in deprecated. Please refer to the [onchain 1155 minting guide](/protocol-sdk/creator/onchain) moving forward. ## Creating an 1155 with a split payout [0xSplits](https://splits.org/) can be used to split the payout for 1155s among multiple recipients. This is done by first creating a 0xSplit recipient contract at a deterministic address based on the recipient addresses and the split percentages, and then creating the 1155 token with the 0xSplit recipient contract as the payout recipient. Due to security limitations, this must be done in two separate transactions. **Note: splits are not currently supported with Premints, and are only supported with onchain creation using `create1155()`.** Here is an example using the [0xSplits SDK](https://docs.splits.org/sdk/splits-v1): :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: data.ts // [!include ~/snippets/protocol-sdk/create/data.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/create1155WithSplits.ts] ``` ```ts twoslash [data.ts] // [!include ~/snippets/protocol-sdk/create/data.ts] ``` ```ts twoslash [config.ts] filename="config.ts" // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ## withdrawRewards Protocol Rewards and [onchain Secondary Royalties](https://support.zora.co/en/articles/2519873) can be withdrawn in a single transaction by executing the parameters generated from calling `withdrawRewards` on the `creatorClient`. The `withdrawRewards` function prepares a multicall transaction that withdraws both the rewards and royalties balances for each ERC20 token associated with the specified account. When using the Protocol SDK, any account can execute the transaction to withdraw rewards on behalf of another account. However, the rewards and royalties will always be sent to the original balance holder. This feature allows for scenarios such as a bot withdrawing rewards and covering the gas costs on behalf of the creator. The `withdrawFor` parameter specifies the account for which to withdraw the rewards. The `account` parameter is set to the account that will execute the transaction. By default, both Protocol Rewards and Secondary Royalties are withdrawn. If you wish to exclude Secondary Royalties from the withdrawal, set the `claimSecondaryRoyalties` parameter to `false`. ### Usage :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/create/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/create/withdrawRewards.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/create/config.ts] ``` ::: ### Returns `{ parameters: SimulateContractParameters }` #### parameters * **Type:** `SimulateContractParameters` Prepared parameters for simulating/writing a transaction using viem/wagmi. ### Parameters #### withdrawFor * **Type:** `Address` The account that holds the balance to withdraw for. Any outstanding ETH or ERC20 balance will be transferred to that account. #### claimSecondaryRoyalties (optional) * **Type:** `boolean` Set this to `false` to disable claiming secondary royalties. #### account * **Type:** `Address` | `Account` The account to execute the transaction. Any account can withdraw rewards for another account, but the rewards will always be sent to the account that holds the balance. ## `buy1155OnSecondary` The `buy1155OnSecondary` function on the `collectorClient` allows you to purchase ERC1155 tokens on the secondary market. This function prepares a transaction with slippage protection for buying a specified quantity of 1155 tokens using ETH. ### Important Limitations Before using this function, ensure that the following conditions are met: 1. The ERC1155 token must be configured to use the ZoraTimedSaleStrategy. 2. The primary mint period for the token must have ended. 3. The secondary market for the token must have been launched. 4. There must be sufficient liquidity in the pool for the swap. 5. The buyer must have enough ETH to cover the purchase price, including any slippage. If any of these conditions are not met, the function will return an error and the transaction cannot be executed. Always check the `error` field in the returned object before proceeding with the transaction. ### Usage ```ts twoslash [example.ts] // [!include ~/snippets/protocol-sdk/collect/buy1155OnSecondary.ts] ``` ### Returns `{ error?: string, parameters?: SimulateContractParameters, price: QuotePrice }` #### error * **Type:** `string | undefined` An error message if the operation cannot be completed. This could be due to reasons such as insufficient balance, market not being active, or other contract-specific issues. #### parameters * **Type:** `SimulateContractParameters | undefined` Prepared parameters for simulating/writing a transaction using viem/wagmi. This will be undefined if there's an error. #### price * **Type:** `QuotePrice` Detailed information about the price breakdown for the purchase. This includes: * **wei:** Price breakdown in wei * **perToken:** Price per individual token in wei * **total:** Total price for all tokens in wei * **sparks:** Price breakdown in sparks * **perToken:** Price per individual token in sparks * **total:** Total price for all tokens in sparks * **usdc:** Async function that returns the price breakdown in USDC * **perToken:** Price per individual token in USDC * **total:** Total price in USDC ### Parameters #### contract * **Type:** `Address` The address of the ERC1155 contract to buy an 1155 of. #### tokenId * **Type:** `bigint` The ID of the ERC1155 token to buy. #### quantity * **Type:** `bigint` The quantity of 1155 tokens to buy. #### account * **Type:** `Address | Account` The account to use for the transaction. This can be either an Ethereum address or a full Account object. This account will use its ETH balance to complete the purchase. #### slippage (optional) * **Type:** `number` * **Default:** `0.005` (0.5%) The maximum acceptable slippage percentage for the transaction. This helps protect against price movements between the time the transaction is submitted and when it's executed. Slippage protection when buying ensures that the desired quantity of ERC1155 is received. Additional ETH will be sent to account for slippage, and any excess ETH will be refunded at the end of the transaction. #### recipient (optional) * **Type:** `Address` The address that will receive the purchased 1155 tokens. If not specified, the tokens will be sent to the `account` address. ## `getSecondaryInfo` The `getSecondaryInfo` function on the `collectorClient` allows you to retrieve information about the secondary market configuration and status for a specific ERC1155 token. ### Usage ```ts twoslash import { createCollectorClient } from "@zoralabs/protocol-sdk"; import { useChainId, usePublicClient } from "wagmi"; const chainId = useChainId(); const publicClient = usePublicClient()!; const collectorClient = createCollectorClient({ chainId, publicClient }); const secondaryInfo = await collectorClient.getSecondaryInfo({ contract: "0xd42557f24034b53e7340a40bb5813ef9ba88f2b4", tokenId: 4n, }); if (secondaryInfo) { // @noErrors secondaryInfo. // ^| } ``` ### Returns `SecondaryInfo` | `undefined` If the minter is not configured to use the ZoraTimedSaleStrategy, then `undefined` is returned. #### secondaryActivated * **Type:** `boolean` Boolean indicating if the secondary market has been launched. #### pool * **Type:** `Address` The Uniswap pool address for this token. #### erc20z * **Type:** `Address` The ERC20z token address used for the secondary market. #### name * **Type:** `string` The name of the ERC20z token. #### symbol * **Type:** `string` The symbol of the ERC20z token. #### saleStart * **Type:** `bigint` Earliest time in seconds when tokens can be minted. #### saleEnd * **Type:** `bigint | undefined` Latest time in seconds when tokens can be minted. This gets set after the market countdown has started. #### marketCountdown * **Type:** `bigint | undefined` The amount of time in seconds after the `minimumMintsForCountdown` is reached until the secondary market can be launched. #### minimumMintsForCountdown * **Type:** `bigint | undefined` The minimum quantity of tokens that must have been minted to launch the countdown. #### mintCount * **Type:** `bigint` The total number of tokens that have been minted so far. ### Parameters #### contract * **Type:** `Address` The ERC1155 contract address to retrieve secondary market information for. #### tokenId * **Type:** `bigint` The token ID to retrieve secondary market information for. ## `getToken` The Collector Client can be used to get token 1155s, 721s, and premints with a function `getToken()`. The type of token get is determined by the `mintType` parameter, which can be set to either `1155`, `721`, or `premint`. Depending on the `mintType` additional parameters must be passed. The `getToken()` function returns both information about the token, in the `token` object, and a function `prepareMint` which takes a quantity to mint and returns the transaction parameters to mint the token, costs to mint the token, and any necessary erc20 approvals that must be executed before minting the token. ### Usage ```tsx twoslash import { useChainId, usePublicClient, useAccount, useWriteContract } from 'wagmi'; import { getToken } from "@zoralabs/protocol-sdk"; const chainId = useChainId(); const publicClient = usePublicClient(); // get the item that can be minted, and a function to prepare // a mint transaction const { token, prepareMint } = await getToken({ publicClient, // contract address token belongs to tokenContract: "0x1234567890123456789012345678901234567890", // can be set to 1155, 721 mintType: "1155", }); // the function returns a `token` object // containing information about the item that can be minted // @noErrors token. // ^| // The `prepareMint` function can be used to prepare a transaction // to mint x quantity of tokens to a recipient const { address } = useAccount(); const { parameters, costs } = prepareMint({ minterAccount: address!, quantityToMint: 3n }); const { writeContract } = useWriteContract(); // When the button is clicked, the transaction // to mint 3 tokens is written to the network // costs to mint the 3 tokens can be retrieved // from the returned `cost` object // @noErrors costs. // ^| ``` #### Minting the returned token The `getToken()` function returns a [prepareMint](#preparemint) function that can be used to prepare a mint transaction. The `prepareMint` function takes a `minterAccount` and `quantityToMint` parameter and returns the transaction parameters to mint the token, costs to mint the token, and any necessary erc20 approvals that must be executed before minting the token. The returned `parameters` object can be passed to a `WalletClient`'s `writeContract` function to mint the token. ```tsx twoslash import React from 'react'; // ---cut--- import { useChainId, usePublicClient, useAccount, useWriteContract } from 'wagmi'; import { getToken } from "@zoralabs/protocol-sdk"; const chainId = useChainId(); const publicClient = usePublicClient()!; // get the item that can be minted, and a function to prepare // a mint transaction const { prepareMint, primaryMintActive } = await getToken({ // contract address token belongs to tokenContract: "0x1234567890123456789012345678901234567890", // can be set to 1155, 721, or premint mintType: "1155", tokenId: 1n, publicClient }); // The `prepareMint` function can be used to prepare a transaction // to mint x quantity of tokens to a recipient const { address } = useAccount(); const data = prepareMint && prepareMint({ minterAccount: address!, quantityToMint: 3n }); const { writeContract } = useWriteContract(); // When the button is clicked, the transaction // to mint 3 tokens is written to the network ``` ### Parameters ```ts twoslash import { type GetMintParameters } from '@zoralabs/protocol-sdk' ``` #### tokenContract `Address` The address of the contract that the token belongs to. #### mintType `"1155" | "721" | "premint"` The type of the collection to get the token from. #### tokenId `bigint | undefined` The token id to get, only applicable for 1155s. #### uid `number | undefined` The uid to get, only applicable for premints. #### preferredSaleType (optional) `"fixedPrice" | "erc20" | "allowlist" | "premint" | "timed"` Optional preferred sale type of the minter to use for the token, only applicable for onchain 1155s. ### Usage Examples ### For ERC1155 Mint ```tsx twoslash import { type GetMintParameters } from '@zoralabs/protocol-sdk' // ---cut--- const params: GetMintParameters = { tokenContract: "0x1234567890123456789012345678901234567890", mintType: "1155", tokenId: 1n }; ``` #### For ERC721 Mint ```tsx twoslash import { type GetMintParameters } from '@zoralabs/protocol-sdk' // ---cut--- const params: GetMintParameters = { tokenContract: "0x1234567890123456789012345678901234567890", mintType: "721" }; ``` #### For Premint ```tsx twoslash import { type GetMintParameters } from '@zoralabs/protocol-sdk' // ---cut--- const params: GetMintParameters = { tokenContract: "0x1234567890123456789012345678901234567890", mintType: "premint", uid: 5 }; ``` ### Return Type ```ts twoslash import { type MintableReturn } from '@zoralabs/protocol-sdk' ``` `Promise` Where `MintableReturn` is defined as: ```ts twoslash import { SalesConfigAndTokenInfo, PrepareMint } from '@zoralabs/protocol-sdk' // ---cut--- type MintableReturn = { /** Token information */ token: SalesConfigAndTokenInfo; /** If the primary mint is active, the end time of the primary mint, if there is an end time */ primaryMintEnd?: bigint; /** If the secondary market is active */ secondaryMarketActive: boolean; } & ( | { primaryMintActive: true; /** Function that takes a quantity of items to mint and returns a prepared transaction and the costs to mint that quantity. If the primary mint is not active, it will be undefined. */ prepareMint: PrepareMint; } | { primaryMintActive: false; prepareMint: undefined; } ); ``` #### token `OnchainSalesConfigAndTokenInfo | PremintSalesConfigAndTokenInfo` An object containing information about the token that can be minted, including contract details, sales configuration, and token-specific information. #### primaryMintActive `boolean` Indicates whether the primary mint is currently active. #### primaryMintEnd `number | undefined` The timestamp when the primary mint ends, if applicable. #### secondaryMarketActive `boolean` Indicates whether the secondary market is currently active. If so `buy1155OnSecondary` and `sell1155OnSecondary` will be active on the token. #### prepareMint `PrepareMint | undefined` A function that prepares the mint transaction, if the primary mint is active. Otherwise, it is undefined. ```ts twoslash import { type MintParametersBase, type PrepareMintReturn } from "@zoralabs/protocol-sdk"; type PrepareMint = (params: MintParametersBase) => PrepareMintReturn; ``` It takes a `MintParametersBase` as the argument, which contains the following properties: * `minterAccount`: The account that will execute the mint transaction. * `quantityToMint`: The quantity of tokens to mint. Defaults to 1. * `mintComment`: An optional comment to add to the mint transaction. * `mintReferral`: (optional) address that will receive the mint referral reward. * `mintRecipient`: (optional) address to receive the minted tokens. Defaults to the minting account. * `firstMinter`: (optional) address to receive the first minter reward, if the mint is a premint. * `allowListEntry`: (optional) allow list entry to use for the mint, if the mint is an allow list mint. It returns a `PrepareMintReturn` object with the following properties: * `parameters`: The transaction parameters to mint the token. * `erc20Approval`: Any necessary ERC20 approvals that must be executed before minting the token (if applicable). * `costs`: The costs associated with minting the token. ## `getTokensOfContract` **Both onchain** and **premint (gaslessly created)** tokens of a Zora 1155 contract can be retrieved using the Collector Client function `getTokensOfContract()` and passing a token contract address. The function returns a `tokens` array with an item for each token of the contract. Each item in `tokens` contains information the token in the `token` object, and has a function `prepareMint`. The `prepareMint` function takes a quantity to mint and returns the transaction parameters to mint the token, costs to mint the token, and any necessary erc20 approvals that must be executed before minting the token. ### Usage ```tsx twoslash import { useChainId, usePublicClient, useAccount, useWriteContract } from 'wagmi'; import { getTokensOfContract } from "@zoralabs/protocol-sdk"; const chainId = useChainId(); const publicClient = usePublicClient(); // get the item that can be minted, and a function to prepare // a mint transaction const { tokens, contract } = await getTokensOfContract({ // collection address to mint tokenContract: "0x1234567890123456789012345678901234567890", publicClient }); // the function returns an array of `tokens`, with each item // containing information about the item that can be minted // @noErrors tokens[0]!.token. // ^| // The `prepareMint` function of the any returned token // can be used to prepare a transaction to mint x quantity of // that token to a recipient const { address } = useAccount(); const { parameters, costs } = tokens[0]!.prepareMint({ minterAccount: address!, quantityToMint: 3n }); const { writeContract } = useWriteContract(); // When the button is clicked, the transaction to mint 3 tokens // of the first returned token is written to the network // costs to mint the 3 tokens can be retrieved // from the returned `cost` object // @noErrors costs. // ^| ``` ### Return Type Returns an array of [MintableReturn](/protocol-sdk/collect/getToken#return-type) objects. ### Parameters #### tokenContract `Address` The address of the 1155 contract to get the tokens of. #### preferredSaleType (optional) `"fixedPrice" | "erc20" | "allowlist" | "premint" | "timed"` Optional preferred sale type of the minter to use for the token, only applicable for onchain 1155s. ## `mint` The Collector Client can be used to prepare transactions for minting 1155s, 721s, and premints with a function `mint()`. The type of item to mint is determined by the `mintType` parameter, which can be set to either `1155`, `721`, or `premint`. Depending on the `mintType` additional parameters must be passed. ### Usage ```tsx twoslash import { useChainId, usePublicClient, useWriteContract } from 'wagmi'; import { createCollectorClient } from "@zoralabs/protocol-sdk"; const chainId = useChainId(); const publicClient = usePublicClient(); // set to the chain you want to interact with const collectorClient = createCollectorClient({ chainId, publicClient }); const { parameters } = await collectorClient.mint({ // collection address to mint tokenContract: "0x1234567890123456789012345678901234567890", // quantity of tokens to mint quantityToMint: 5, // can be set to 1155, 721, or premint // @noErrors mintType: "", // ^| }); const { writeContract } = useWriteContract(); //Clicking the button writes the mint transaction to the network ``` #### Mint 1155s 1155s can be minted by calling `mint()` with `mintType` set to `1155`, and the `tokenId` set to the token id to mint: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/collect/config.ts] // @filename: data.ts // [!include ~/snippets/protocol-sdk/collect/data.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/collect/mint1155.ts] ``` ```ts twoslash [data.ts] // [!include ~/snippets/protocol-sdk/collect/data.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/collect/config.ts] ``` ::: #### Mint ERC20 based 1155s When minting ERC20 based 1155s, an additional approval to transfer ERC20s to an address must be executed before minting.\ In the case that the 1155 to mint is an ERC20 based mint, the `mint` function will return an `erc20Approval` which contains information about which ERC20 token to approve, the amount to approve, and the address to approve to.\ Before executing the mint transaction, the approval transaction must be executed: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/collect/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/collect/minterc20.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/collect/config.ts] ``` ::: #### Mint 721s 721s can be minted by calling `mint()` with `mintType` set to `721`. No `tokenId` is set as the token id is determined by auto-incrementing token ids; one tokenId will be created & minted for each `quantityToMint`: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/protocol-sdk/collect/config.ts] // @filename: data.ts // [!include ~/snippets/protocol-sdk/collect/data.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/collect/mint721.ts] ``` ```ts twoslash [data.ts] // [!include ~/snippets/protocol-sdk/collect/data.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/protocol-sdk/collect/config.ts] ``` ::: #### Earning Mint Referral Rewards To earn a mint referral reward, pass in the `mintReferral` argument to the `mint` function: :::code-group ```ts twoslash [example.ts] // @filename: create1155.ts // [!include ~/snippets/protocol-sdk/collect/create1155.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/protocol-sdk/collect/mintReferral.ts] ``` ```ts twoslash [create1155.ts] // [!include ~/snippets/protocol-sdk/collect/create1155.ts] ``` ::: #### Getting mint costs The `cost` object returned from the `mint()` function can be used to get the costs to mint x quantity of the token. :::code-group ```ts twoslash [example.ts] // @filename: data.ts // [!include ~/snippets/protocol-sdk/collect/data.ts] // @filename: example.ts // ---cut--- import { usePublicClient, useAccount } from "wagmi"; import { createCollectorClient } from "@zoralabs/protocol-sdk"; import { chainId, publicClient } from "./config"; import { tokenAddress, tokenId } from "./data"; const publicClient = usePublicClient(); const collectorClient = createCollectorClient({ chainId, publicClient }); const { address } = useAccount(); const { prepareMint } = await collectorClient.getToken({ // 1155 contract address collection: tokenAddress, // 1155 token id tokenId, // @noErrors mintType: "", // ^| }); // get the costs by calling the returned `prepareMint` function // with the quantity to mint const { costs } = prepareMint({ minterAccount: address!, quantityToMint: 3n }); // @noErrors costs. // ^| ``` ```ts twoslash [data.ts] // [!include ~/snippets/protocol-sdk/collect/data.ts] ``` ::: ### Parameters ```ts twoslash import { type MakeMintParametersArguments } from "@zoralabs/protocol-sdk"; const params: MakeMintParametersArguments = { tokenContract: "0x1234567890123456789012345678901234567890", mintType: "1155", tokenId: 1n, minterAccount: "0x1234567890123456789012345678901234567890", quantityToMint: 5, mintReferral: "0x1234567890123456789012345678901234567890", mintRecipient: "0x1234567890123456789012345678901234567890", } ``` #### tokenContract `Address` The address of the contract to mint from. #### mintType `"1155" | "721" | "premint"` The type of token to mint. #### tokenId `bigint` (only for 1155 mints) The token ID to mint for ERC1155 tokens. #### uid `number` (only for premint mints) The unique identifier of the premint to mint. #### minterAccount `Account | Address` The account that will execute the mint transaction. #### quantityToMint `number | bigint` The quantity of tokens to mint. Defaults to 1. #### mintComment `string` (optional) An optional comment to add to the mint transaction. #### mintReferral `Address` (optional) The address that will receive the mint referral reward, if applicable. #### mintRecipient `Address` (optional) The address that will receive the minted tokens. If not specified, defaults to the minting account. #### firstMinter `Address` (optional) For premint mints, the address that will receive the first minter reward if this mint brings the premint onchain. Do note that premint is a deprecated feature as we have moved to being onchain first with our mints. #### allowListEntry `AllowListEntry` (optional) For allowlist mints, the information for the allowlist entry. #### preferredSaleType (optional) `"fixedPrice" | "erc20" | "allowlist" | "premint" | "timed"` Optional preferred sale type of the minter to use for the token, only applicable for onchain 1155s. ### Return Type Returns an object with the following properties: * `parameters`: The parameters for the mint transaction. * `costs`: The costs for the mint transaction. ## `sell1155OnSecondary` The `sell1155OnSecondary` function on the `collectorClient` allows you to sell Zora ERC1155 tokens for ETH on the secondary market. This function prepares a transaction with slippage protection for selling a specified quantity of tokens for ETH. ### Important Limitations Before using this function, ensure that the following conditions are met: 1. The ERC1155 token must be configured to use the ZoraTimedSaleStrategy. 2. The primary mint period for the token must have ended. 3. The secondary market for the token must have been launched. 4. There must be sufficient liquidity in the pool for the swap. 5. The seller must own the tokens they are attempting to sell. If any of these conditions are not met, the function will return an error and the transaction cannot be executed. Always check the `error` field in the returned object before proceeding with the transaction. ### Usage ```ts twoslash [example.ts] // [!include ~/snippets/protocol-sdk/collect/sell1155OnSecondary.ts] ``` ### Returns `{ error?: string, parameters?: SimulateContractParameters, price: QuotePrice }` #### error * **Type:** `string | undefined` An error message if the operation cannot be completed. This could be due to reasons such as insufficient token balance, market not being active, or other contract-specific issues. #### parameters * **Type:** `SimulateContractParameters | undefined` Prepared parameters for simulating/writing a transaction using viem/wagmi. This will be undefined if there's an error. #### price * **Type:** `QuotePrice` Detailed information about the price breakdown for the sale. This includes: * **wei:** Price breakdown in wei * **perToken:** Price per individual token in wei * **total:** Total price for all tokens in wei * **sparks:** Price breakdown in sparks * **perToken:** Price per individual token in sparks * **total:** Total price for all tokens in sparks * **usdc:** Async function that returns the price breakdown in USDC * **perToken:** Price per individual token in USDC * **total:** Total price in USDC ### Parameters #### contract * **Type:** `Address` The address of the ERC1155 contract to sell an 1155 of. #### tokenId * **Type:** `bigint` The ID of the ERC1155 token to sell. #### quantity * **Type:** `bigint` The quantity of 1155 tokens to sell. #### account * **Type:** `Address | Account` The account to use for the transaction. This can be either an Ethereum address or a full Account object. This account must have the necessary token balance to complete the sale. #### slippage (optional) * **Type:** `number` * **Default:** `0.005` (0.5%) The maximum acceptable slippage percentage for the transaction. This helps protect against price movements between the time the transaction is submitted and when it's executed. Slippage protection when selling ensures that a minimum amount of ETH is received for the sale. #### recipient (optional) * **Type:** `Address` The address that will receive the ETH from the sale. If not specified, the ETH will be sent to the `account` address. ## Cointags Cointags lets creators connect their posts with onchain communities through by tagging their posts with their coins. When someone mints a creator's post, a portion of the creator rewards automatically: * Goes to buying and burning an ERC20 token of their choice * Goes to the creator as their reward For more details about using Cointags as a creator, see the [Cointags Support Article](https://support.zora.co/en/articles/4185217). > **Note**: Cointags use UniswapV3Pools to buy the corresponding ERC20 token for burning. Currently Cointags only work with Uniswap V3 pools. The pool must have WETH as one of its tokens. ### Contract Architecture The protocol consists of two main contracts: | Contract | Description | | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | [`CointagFactoryImpl.sol`](https://github.com/ourzora/zora-protocol/blob/main/packages/cointags/src/CointagFactoryImpl.sol) | CointagFactory implementation contract for deterministically deploying `Cointag` contracts | | [`CointagImpl.sol`](https://github.com/ourzora/zora-protocol/blob/main/packages/cointags/src/CointagImpl.sol) | Cointag implementation contract | #### Deterministic Deployment The `CointagFactory` is deployed deterministically at the address `0x7777777BbD0b88aD5F3b5f4c89C6B60D74b9774F` on [Base](https://basescan.org/address/0x7777777BbD0b88aD5F3b5f4c89C6B60D74b9774F) and [Zora Network](https://explorer.zora.energy/address/0x7777777BbD0b88aD5F3b5f4c89C6B60D74b9774F?). The `CointagFactory` uses `solady`'s [CREATE3](https://github.com/Vectorized/solady/blob/main/src/utils/CREATE3.sol) for deterministically deploy `Cointag` contracts, ensuring that: * Each combination of creator, pool, and burn percentage results in the same address across all chains. * Deployed `Cointag` addresses are consistent regardless of implementation or code versions. * `Cointag` addresses can be predicted before deployment. ### Protocol Flow The following diagram illustrates the sequence of interactions in the protocol: ![Cointag Sequence Diagram](/uml/cointag-sequence.svg) #### Sequence Breakdown * **Setting Up a Cointag and 1155 Post**: * The creator deploys a new `Cointag` instance through the `CointagFactory`. * The creator sets their 1155 post's reward recipient to the `Cointag` address. * **Pulling to Buy, Burn, and Distribute Rewards**: * When someone mints a post, creator rewards are deposited into the `ProtocolRewards` contract, with the `Cointag` as the recipient. * Anyone can trigger the distribution of accumulated rewards by calling `pull()` on the `Cointag` contract; in the `pull()` function, the `Cointag`: * Withdraws ETH from the protocol rewards. * Wraps the buy/burn percentage as WETH. * Swaps the WETH for the target ERC20. * Burns the received ERC20 tokens. * Deposits the remaining ETH back to the protocol rewards for the creator. * **Creator Reward Withdrawal**: * The creator can withdraw their share of rewards that were deposited in the `pull()` step from the protocol rewards contract at any time. The following class diagram illustrates the contract relationships in the protocol: ![Cointag Class Diagram](/uml/cointag-objects.svg) #### Auto-pulling bot Zora has a bot that automatically searches for `Cointag`s with an outstanding protocol rewards balance and pulls them. ### Error Handling If any step in the buy & burn process fails, all ETH is sent to the creator. ### Upgradeability `Cointag`s are upgradeable using the UUPS (Universal Upgradeable Proxy Standard) pattern with additional safety checks: * Only the owner (creator) can initiate upgrades * Similar to the Zora 1155 contract's upgradeability, new implementations must be registered in the `UpgradeGate`, which is controlled by a Zora team multisig to prevent malicious upgrades. ## Comments The Comments contract allows for comments to be made on any Zora 1155 token. Only 1155 token owners or holders can comment on that token. If the commenter is an owner, they must pay a Spark to comment. If the commenter is a creator, they can comment for free. Comments can be Sparked by anyone, meaning that the Sparker must send a Spark as a form of liking a comment. ### Contracts The protocol consists of a single upgradeable contract called `Comments`, that is deployed deterministically to the same address on all chains. There is also a helper contract called `CallerAndCommenter` that enables minting and commenting in a single transaction. | Contract | Deterministic Address | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------- | | Comments | [0x7777777C2B3132e03a65721a41745C07170a5877](https://explorer.zora.energy/address/0x7777777C2B3132e03a65721a41745C07170a5877) | | CallerAndCommenter | [0x77777775C5074b74540d9cC63Dd840A8c692B4B5](https://explorer.zora.energy/address/0x77777775C5074b74540d9cC63Dd840A8c692B4B5) | ### Spark value distribution When a commenter pays a Spark to comment on a token, the Spark value (less a protocol fee) is sent to the token's creator reward recipient. When a commenter pays a Spark to reply to a comment, the Spark value (less a protocol fee) is sent to the original commenter as a reward. When a Spark is used to Spark a comment, the Spark value (less a protocol fee) is sent to the commenter. For each Spark value transaction, a 30% protocol fee is taken. If a referrer is specified, 20% goes to the referrer and 10% goes to Zora. Otherwise, 30% goes to Zora. A referrer can be a third-party developer that surfaces the ability to comment on a site or app, and the referrer address is specified as an argument when commenting or Sparking. ### Building on comments and earning referral rewards Developers can integrate the Comments contract into their platform from day one and earn referral rewards when users when users spark a comment on their platform. When a referral address is specified when minting or sparking, 20% of the total Spark value is paid out to the referrer. To earn referral rewards, developers should [specify a referrer address in the function calls](#specifying-a-referrer) ### What is a Spark? [A Spark is a fundamental concept in the Zora ecosystem.](https://support.zora.co/en/articles/1829633) It serves as a unit of value and can be used to pay for mints and other interactions: * Sparks are [1155 tokens on the Zora network.](https://explorer.zora.energy/address/0x7777777b3eA6C126942BB14dD5C3C11D365C385D) They can be purchased with credit/debit cards or ETH, primarily used to cover minting fees for NFTs on Zora. * **Each Spark has an immutable value of 0.000001 ETH** * In the context of the Comments contract, Sparks are used to pay for comments (for non-creators) and to "like" or endorse comments made by others. * Sparks can be unwrapped by their owner, allowing the underlying ETH value to be used for other transactions. ### Backfilled legacy comments Before the Comments contract's deployment, comments were made on other contracts that emitted `MintComment` events. To enable users to reply to or Spark these older comments, we backfill the new Comments contract with legacy comment data. This process: 1. Saves onchain unique IDs for the legacy comments. 2. Allows users to interact with pre-existing comments since they have an onchain ID. ### Usage #### Commenting Commenting can be done by calling the `comment` function, paying with the equivalent value in Sparks: ```solidity interface IComments { struct CommentIdentifier { address commenter; address contractAddress; uint256 tokenId; bytes32 nonce; } /// @notice Creates a new comment. Equivalent Sparks value in ETH must be sent with the transaction. Must be a holder or creator of the referenced 1155 token. /// If not the owner, must send at least 1 Spark. Sparks are transferred from the commenter to the Sparks recipient (either the creator when there is no replyTo, or the replyTo commenter). /// @param contractAddress The address of the contract /// @param tokenId The token ID /// @param commenter The address of the commenter /// @param text The text content of the comment /// @param replyTo The identifier of the comment being replied to (if any) /// @return commentIdentifier The identifier of the created comment, including the nonce function comment( address commenter, address contractAddress, uint256 tokenId, string calldata text, CommentIdentifier calldata replyTo, address referrer ) external payable returns (CommentIdentifier memory commentIdentifier) { } } ``` Example usage with `@zoralabs/protocol-deployments` and `viem`: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/comment.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: Note: The `getSparksValue` function is used to calculate the equivalent ETH value for a given number of sparks. It's implementation is not shown here but is crucial for determining the correct payment amount. #### Replying to a comment When a comment is created, it is associated with a unique identifier. This identifier is used to reply to the comment. The unique identifier contains an autoincrementing nonce generated by the contract that is used to ensure that the identifier is unique for a given commenter, contract, and tokenId. When replying to a comment, the replyTo argument is the identifier of the comment being replied to. ```solidity interface IComments { struct CommentIdentifier { address commenter; address contractAddress; uint256 tokenId; bytes32 nonce; } function comment( address commenter, address contractAddress, uint256 tokenId, string calldata text, // this identifies the comment that we are replying to CommentIdentifier calldata replyTo, // [!code focus] address referrer ) external payable returns (CommentIdentifier memory commentIdentifier) { } } ``` Example usage with `@zoralabs/protocol-deployments` and `viem`: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: comment.ts // [!include ~/snippets/contracts/comments/comment.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/reply.ts] ``` ```ts twoslash [comment.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: comment.ts // ---cut--- // [!include ~/snippets/contracts/comments/comment.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: #### Sparking a comment Sparking a comment is done by calling the `sparkComment` function, paying with the equivalent value in Sparks. Sparking a comment is similar to liking a comment, except it is liked with the value of Sparks attached. The Spark value gets sent to the commenter, with a fee taken out. ```solidity interface IComments { struct CommentIdentifier { address commenter; address contractAddress; uint256 tokenId; // nonce is a unique value that is generated when a comment is created. It is used to ensure that the comment identifier is unique // for a given commenter, contract, and tokenId. bytes32 nonce; } /// @notice Sparks a comment. Equivalent Sparks value in ETH to sparksQuantity must be sent with the transaction. Sparking a comment is /// similar to liking it, except it is liked with the value of Sparks attached. The Spark value gets sent to the commenter, with a fee taken out. /// @param commentIdentifier The identifier of the comment to Spark /// @param sparksQuantity The quantity of Sparks to send /// @param referrer The referrer of the comment function sparkComment(CommentIdentifier calldata commentIdentifier, uint64 sparksQuantity, address referrer) public payable; } ``` Example usage with `@zoralabs/protocol-deployments` and `viem`: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/sparking.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: #### Minting and commenting When minting with the `ZoraTimedSaleStrategy`, which is the default way to mint on Zora, a comment can be included at no additional cost by calling the function `timedSaleMintAndComment()` on the `CallerAndCommenter` helper contract. While the comment itself is free, the standard mint fee still needs to be sent with the transaction. ```solidity // Deployed to 0x77777775C5074b74540d9cC63Dd840A8c692B4B5 on all chains supported by Zora. interface ICallerAndCommenter { /// @notice Mints tokens and adds a comment, without needing to pay a spark for the comment. /// @dev The payable amount should be the total mint fee. No spark value should be sent. /// @param commenter The address of the commenter /// @param quantity The number of tokens to mint /// @param collection The address of the 1155 collection to mint from /// @param tokenId The 1155 token Id to mint /// @param mintReferral The address to receive mint referral rewards, if any /// @param comment The comment to be added. If empty, no comment will be added. /// @return The identifier of the newly created comment function timedSaleMintAndComment( address commenter, uint256 quantity, address collection, uint256 tokenId, address mintReferral, string calldata comment ) external payable returns (IComments.CommentIdentifier memory); } ``` Example usage with `@zoralabs/protocol-deployments` and `viem`: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/mintAndComment.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: #### Specifying a Referrer When calling the `comment`, `sparkComment`, or related functions, a referrer address can be specified. This allows third-party developers to earn a portion of the protocol fee when users interact with the Comments contract through on their platform. To specify a referrer, simply include the referrer's address as the last argument in the function call: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/referrer.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: #### Commenting as a smart wallet owner An account that is a smart wallet owner can comment on a token, if a smart wallet is an owner or creator of the token. In this case, the smart wallet address should be passed as the `smartWallet` argument when calling the `comment` function. The function will check if the smart wallet or the account that is creating the comment is an owner or creator of the token, but will attribute the comment to the account that is calling the comment function. Correspondingly, the `commenter` argument must match the account that is creating the comment. Example usage with `@zoralabs/protocol-deployments` and `viem`: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/commentWithSmartWallet.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: #### Cross-Chain commenting, sparking, and minting with comments An account can sign a permit to comment, spark a comment, or mint and comment on their behalf, and that permit can be used to execute the action onchain. This enables cross-chain functionality for these actions by validating that the signer of the message is the original commenter, sparker, or minter. Here's how it works: 1. When creating the permit, the user specifies two chain IDs: * `sourceChainId`: The chain ID where the permit is being signed. * `destinationChainId`: The chain ID where the permit should be executed. 2. To enable cross-chain functionality: * Set `sourceChainId` to the current chain where you're signing the permit. * Set `destinationChainId` to the chain ID of the target blockchain where you want the action to be executed. 3. The permit can then be signed on a source chain and submitted to the appropriate contract on the destination chain, allowing the action to be executed there. For example, if you're signing a permit on Base, but want the action to occur on Zora Network, you would set: * `sourceChainId` to 8453 * `destinationChainId` to 7777777 This process works for: * Commenting (using the `Comments` contract) * Sparking a comment (using the `Comments` contract) * Minting and commenting (using the `CallerAndCommenter` helper contract) 1. Example cross-chain commenting with Relay: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/permitComment.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: 2. Example cross-chain sparking with Relay: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: comment.ts // [!include ~/snippets/contracts/comments/comment.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/permitSparkComment.ts] ``` ```ts twoslash [comment.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: comment.ts // --cut-- // [!include ~/snippets/contracts/comments/comment.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: 3. Example cross-chain minting and commenting with Relay: :::code-group ```ts twoslash [example.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: comment.ts // [!include ~/snippets/contracts/comments/comment.ts] // @filename: example.ts // ---cut--- // [!include ~/snippets/contracts/comments/permitMintAndComment.ts] ``` ```ts twoslash [comment.ts] // @filename: config.ts // [!include ~/snippets/contracts/comments/config.ts] // @filename: comment.ts // --cut-- // [!include ~/snippets/contracts/comments/comment.ts] ``` ```ts twoslash [config.ts] // [!include ~/snippets/contracts/comments/config.ts] ``` ::: ### Events The `Comments` contract emits the following events: ```solidity interface IComments { /// @notice Event emitted when a comment is created event Commented( bytes32 indexed commentId, // Unique ID for the comment, generated from a hash of the commentIdentifier CommentIdentifier commentIdentifier, // Identifier for the comment, containing details about the comment bytes32 replyToId, // Unique ID of the comment being replied to (if any) CommentIdentifier replyTo, // Identifier of the comment being replied to (if any) uint256 sparksQuantity, // Number of sparks associated with this comment string text, // The actual text content of the comment uint256 timestamp, // Timestamp when the comment was created address referrer // Address of the referrer who referred the commenter, if any ); // Event emitted when a comment is backfilled event BackfilledComment( bytes32 indexed commentId, // Unique identifier for the backfilled comment CommentIdentifier commentIdentifier, // Identifier for the comment string text, // The actual text content of the backfilled comment uint256 timestamp, // Timestamp when the original comment was created bytes32 originalTransactionId // Transaction ID of the original comment (before backfilling) ); // Event emitted when a comment is Sparked event SparkedComment( bytes32 indexed commentId, // Unique identifier of the comment being sparked CommentIdentifier commentIdentifier, // Struct containing details about the comment and commenter uint256 sparksQuantity, // Number of sparks added to the comment address sparker, // Address of the user who sparked the comment uint256 timestamp, // Timestamp when the spark action occurred address referrer // Address of the referrer who referred the sparker, if any ); } ``` When minting and commenting, the `MintedAndCommented` event is emitted from the caller and commenter contract, containing more contextual information about the mint and comment, as well as a link to the comment via the comment identifier. When buying or selling on secondary and commenting, the `SwappedOnSecondaryAndCommented` event is emitted, containing the same contextual information as the minted and commented event, as well as the quantity of tokens bought or sold. ```solidity interface ICallerAndCommenter { /// @notice Emitted when tokens are minted and a comment is added /// @param commentId The unique identifier of the comment /// @param commentIdentifier The struct containing details about the comment /// @param quantity The number of tokens minted /// @param text The content of the comment event MintedAndCommented( bytes32 indexed commentId, IComments.CommentIdentifier commentIdentifier, uint256 quantity, string text ); /// @notice Emitted when tokens are bought or sold on the secondary market and a comment is added /// @param commentId The unique identifier of the comment /// @param commentIdentifier The struct containing details about the comment /// @param quantity The number of tokens bought /// @param comment The content of the comment /// @param swapDirection The direction of the swap (BUY or SELL) event SwappedOnSecondaryAndCommented( bytes32 indexed commentId, IComments.CommentIdentifier commentIdentifier, uint256 indexed quantity, string comment, SwapDirection indexed swapDirection ); } ``` ## Creating a Token Calling `setupNewTokenWithCreateReferral` on a deployed 1155 contract will create a new token. In addition, by passing in your address as the `createReferral` will yield you rewards from those mints. All tokens start at tokenId 1 and increment up. tokenId 0 is reserved for the contract information. `maxSupply` should be set to `MAX_INT` for an open edition. [**View source code here**](https://github.com/ourzora/zora-protocol/blob/ba8548a06b3b003dff59bab1c9aa2738255326c3/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L297C1-L311C24) ```solidity function setupNewTokenWithCreateReferral( string calldata newURI, uint256 maxSupply, address createReferral ) public onlyAdminOrRole(CONTRACT_BASE_ID, PERMISSION_BIT_MINTER) nonReentrant returns (uint256) ``` ### Token Metadata Each token in a Zora 1155 or 721 contract has a metadata uri field which points to a JSON Metadata file, pinned to [IPFS](https://ipfs.tech/), containing the media associated with the token as well as additional descriptive info. [Refer to the SDK guide on building token metadata](/protocol-sdk/metadata/token-metadata) for schematic info, utilities, and sample code to build and pin the json and corresponding assets to IPFS. ### Updating Metadata `updateTokenURI` updates the token URI for a token. Won't work for tokenId 0 since that is reserved for the contract level information. ```solidity function updateTokenURI( uint256 tokenId, string memory _newURI ) ``` Updates the contract metadata. ``` function updateContractMetadata( string memory _newURI, string memory _newName ) ``` ## Creating a contract All 1155 contracts created from Zora are deployed by calling a central factory contract. When calling this factory it will deploy a minimal proxy contract that is upgradeable. All upgrades are opt-in and must be done manually on a per contract basis by the user. * [Factory Contract Code](https://github.com/ourzora/zora-protocol/blob/main/packages/1155-contracts/src/factory/ZoraCreator1155FactoryImpl.sol) * [Deployed Addresses](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-deployments/addresses) * Factory Proxy Address `0x777777C338d93e2C7adf08D102d45CA7CC4Ed021` on all networks **The easiest way to create Zora 1155 contracts using the factory is [by using the sdk.](/protocol-sdk/creator/onchain)** ### Calling the Factory Contract The `createContract` function on the factory is responsible for deploying a new 1155 contract. The `setupActions` parameter allows for multiple actions to be called when deploying the contract. Such as creating a token and sale in the same transaction as deploying the contract. * `contractURI`: The URI for the contract metadata * `name`: The name of the contract * `defaultRoyaltyConfiguration`: The default royalty configuration for the contract * `defaultAdmin`: The default admin for the contract * `setupActions`: The actions to perform on the new contract upon initialization (optional) ``` function createContract( string calldata newContractURI, string calldata name, ICreatorRoyaltiesControl.RoyaltyConfiguration memory defaultRoyaltyConfiguration, address payable defaultAdmin, bytes[] calldata setupActions ) external returns (address) ``` :::note The contract supports multicall so multiple functions can be called to set up the contract in a single transaction. ::: To configure a Splits contract as the recipient address, [follow this guide.](/protocol-sdk/creator/splits) ### Contract URI The Contract URI contains contract specific details. This metadata is stored in a JSON file on IPFS. The uri is retrieved via the `contractURI()` call on the contract. Refer to the [SDK guide on building contract metadata](/protocol-sdk/metadata/contract-metadata) for schematic info and some sample code. ### Setup Actions An optional param that is encoded function data that can be passed in and can call a separate function within the contract. This allows creating a token and setting permissions in the same transaction of creating the contract. Actions that can be called: * Creating a token * Setting the salesConfig * Granting permissions/minter role * Admin minting tokens ## Drop Metadata Renderer ##### Metadata rendering contract for NFTs with individual media assets This contract is in charge of managing and rendering the metadata for Zora drops. A drop is an NFT collection where all the NFTs have individual media assets. Whenever a `tokenURI` is called on an NFT contract it is forwarded to this contract to get metadata for a specific NFT. View the source contract code [here](https://github.com/ourzora/zora-drops-contracts/blob/main/src/metadata/DropMetadataRenderer.sol) and the list of deployed contract addresses [here](https://github.com/ourzora/zora-drops-contracts/tree/main/deployments). * `baseURI`: A common base path that all the assets share and can append the tokenId to the end to get the metadata for an NFT. * `contractURI`: A resource for getting metadata for the contract. Follows the contract-level metadata format described [here](https://docs.opensea.io/docs/contract-level-metadata). * `provenanceHash`: A hash that is used to prove that the order of the images and metadata was set pre-mint, and was not manipulated. * `target`: The address of the NFT contract to get data for. ### updateMetadataBase Updates the baseURI and contractURI. ``` function updateMetadataBase( address target, string memory baseUri, string memory newContractUri ) ``` ### updateMetadataBaseWithDetails Updates the metadata base URI, extension, contract URI and freezing details. ``` function updateMetadataBaseWithDetails( address target, string memory metadataBase, string memory metadataExtension, string memory newContractURI, uint256 freezeAt ) ``` ### updateProvenanceHash Updates the provenance hash stored in the contract. ``` function updateProvenanceHash(address target, bytes32 provenanceHash) ``` ## ERC-20 Minter The ERC20 Minter contract allows you to mint 1155 tokens with ERC20 tokens. This contract is deterministically deployed on all chains that we currently support to this address `0x777777E8850d8D6d98De2B5f64fae401F96eFF31`. When minting with the ERC20 Minter contract there is a 5% reward that is split amongst the reward recipients in the ERC20 currency. A breakdown of these percentages looks like: ##### ERC20 Mint Reward Percentages | Recipient | Amount | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Creator | 95% of earnings from sales | | Mint Fee | 5% of listed purchase price | | Create Referral | 28.57% of Mint Fee (if there is no create referral recipient set the reward will go to Zora) | | Mint Referral | 28.57% of Mint Fee | | First Minter | 14.23% of Mint Fee (if there is no first minter reward recipient set the reward will go to the creator reward recipient and if that does not exist it will go to Zora) | | Zora | 28.63% of Mint Fee | Read functions on the contract: ``` /// @notice Computes the rewards for an ERC20 mint /// @param totalReward The total reward to be distributed /// @return RewardsSettings struct function computePaidMintRewards(uint256 totalReward) public pure returns (RewardsSettings memory); /// @notice Computes the rewards value given an amount and a reward percentage /// @param totalReward The total reward to be distributed /// @param rewardPct The percentage of the reward to be distributed /// @return The reward value function computeReward(uint256 totalReward, uint256 rewardPct) public pure returns (uint256) /// @notice Computes the total reward value for a given amount of ERC20 tokens /// @param totalValue The total number of ERC20 tokens /// @return The total reward value function computeTotalReward(uint256 totalValue) public view returns (uint256) /// @notice The name of the contract which is "ERC20 Minter" /// @return The contract name function contractName() external pure returns (string memory) /// @notice The URI of the contract /// @return The contract URI function contractURI() external pure returns (string memory) /// @notice The version of the contract /// @return The contract version function contractVersion() external pure returns (string memory) /// @notice Gets the create referral address for a given token /// @param tokenContract The address of the token contract /// @param tokenId The ID of the token /// @return The create referral address function getCreateReferral(address tokenContract, uint256 tokenId) public view returns (address createReferral) /// @notice Gets the first minter address for a given token /// @param tokenContract The address of the token contract /// @param tokenId The ID of the token /// @return The first minter address function getFirstMinter(address tokenContract, uint256 tokenId) public view returns (address firstMinter) /// @notice Returns the number of tokens minted per wallet /// @param token The address of the token /// @param tokenId The tokenId of the token /// @param wallet The address of the wallet /// @return the amount minted per wallet function getMintedPerWallet(address token, uint256 tokenId, address wallet) external view returns (uint256); /// @notice Returns the sale config for a given token /// @param tokenContract The TokenContract address /// @param tokenId The ID of the token to get the sale config for /// @return a SalesConfig struct function sale(address tokenContract, uint256 tokenId) external view returns (SalesConfig memory) /// @notice IERC165 interface support /// @param interfaceId The interface ID to check /// @return a boolean value depending if the interface is supported function supportsInterface(bytes4 interfaceId) public pure virtual override(LimitedMintPerAddress, SaleStrategy) returns (bool) /// @notice The percentage of the total value that is distributed as rewards /// @return the reward percentage function totalRewardPct() external view returns (uint256) /// @notice The Zora Reward Recipient address /// @return the Zora Reward Recipient address function zoraRewardRecipientAddress() external view returns (address) ``` Write functions on the contract: ``` /// @notice Mints a token using an ERC20 currency, note the total value must have been approved prior to calling this function /// @param mintTo The address to mint the token to /// @param quantity The quantity of tokens to mint /// @param tokenAddress The address of the token to mint /// @param tokenId The ID of the token to mint /// @param totalValue The total value of the mint /// @param currency The address of the currency to use for the mint /// @param mintReferral The address of the mint referral /// @param comment The optional mint comment function mint( address mintTo, uint256 quantity, address tokenAddress, uint256 tokenId, uint256 totalValue, address currency, address mintReferral, string calldata comment ) external nonReentrant /// @notice Deletes the sale config for a given token function resetSale(uint256 tokenId) external override /// @notice Sets the sale config for a given token function setSale(uint256 tokenId, SalesConfig memory salesConfig) external /// @notice Set the Zora rewards recipient address /// @param recipient The new recipient address function setZoraRewardsRecipient(address recipient) external ``` Structs in the contract: ``` struct RewardsSettings { /// @notice Amount of the create referral reward uint256 createReferralReward; /// @notice Amount of the mint referral reward uint256 mintReferralReward; /// @notice Amount of the zora reward uint256 zoraReward; /// @notice Amount of the first minter reward uint256 firstMinterReward; } struct SalesConfig { /// @notice Unix timestamp for the sale start uint64 saleStart; /// @notice Unix timestamp for the sale end uint64 saleEnd; /// @notice Max tokens that can be minted for an address, 0 if unlimited uint64 maxTokensPerAddress; /// @notice Price per token in ERC20 currency uint256 pricePerToken; /// @notice Funds recipient (0 if no different funds recipient than the contract global) address fundsRecipient; /// @notice ERC20 Currency address address currency; } ``` [Using the ERC20 Minter contract with the protocol sdk](https://ourzora.github.io/zora-protocol/protocol-sdk/mint-client#collecting-an-onchain-1155-token) ## ERC-721 Drop ##### A template NFT contract that is used to create a new collection The NFT contracts created from the `ZoraNFTCreator` are known as an `ERC721Drop`. Each drop contract is cloned from an `implementation` address and receives its own address. Both `Editions` and `Drops` use the same base contract but have different metadata rendering contracts. :::note Every time an NFT is minted and sold using these contracts 5% of the primary sale amount will be reserved by the Zora DAO. Nothing is taken on secondary sales. ::: View the list of deployed contract addresses [here](https://github.com/ourzora/zora-721-contracts/tree/main/addresses) and view the contract source code [here](https://github.com/ourzora/zora-drops-contracts/blob/main/src/ERC721Drop.sol) * `Edition`: A collection where all the NFTs share the same media asset. * `Drop`: A collection where all the NFTs have individual pieces of media. ### Sales Configuration The sales configuration is set when the contract is created. The config holds the internal settings for all the minting/sales parameters. \*Times are Unix Timestamps * `publicSaleStart`: Start time for public minting * `publicSaleEnd`: End time for public minting * `presaleStart`: Start time for private minting * `presaleEnd`: End time for private minting * `publicSalePrice`: Price in the ETH required to mint an NFT * `maxSalePurchasePerAddress`: Max amount of NFTs an address can mint (only for public minting) * `presaleMerkleRoot`: A cryptographic proof that is used for presale minting (allow list) Note that `presaleMerkleRoot` can be set to `0x0000000000000000000000000000000000000000000000000000000000000000` if there are no plans for allow list minting. Current values can be viewed by calling `salesConfig` on the contract and it can be updated by calling `setSalesConfig` with the new parameters. Learn more about creating an allow list [here.](./ERC721Drop#creating-a-presale-allowlist) ``` function setSaleConfiguration( uint104 publicSalePrice, uint32 maxSalePurchasePerAddress, uint64 publicSaleStart, uint64 publicSaleEnd, uint64 presaleStart, uint64 presaleEnd, bytes32 presaleMerkleRoot ) ```
### Collection Size ##### Fixed Size A fixed-size collection is where there is a max number of NFTs that are allowed to be minted from the contract. The max size is set when creating the contract and specifying the `editionSize`. ##### Open Edition An open edition collection has no max amount but instead has a certain time window where minting is open. However, once the period is over then no one can publicly mint anymore. Note, `finalizeOpenEdition` **must be called by an admin** once the minting window has closed to make sure that it's not possible to mint any more NFTs from the contract. ``` function finalizeOpenEdition() ```
### Minting Functions ##### adminMint An admin can mint a certain number of the NFTs to an address without having to pay the base price or protocol rewards. ``` function adminMint(address recipient, uint256 quantity) ``` ##### adminMintAirdrop An admin can mint a single NFT to multiple different addresses in a single transaction without having to pay the base price. The function takes in an array of addresses to mint to. ``` function adminMintAirdrop(address[] calldata recipients) ``` ##### mintWithRewards A public minting function that can be called by anyone once the public sale has started. Minter referral is given to the address that referred the mint. ``` function mintWithRewards( address recipient, uint256 quantity, string calldata comment, address mintReferral ) ``` ##### purchasePresaleWithRewards A private sale function for allowlist minting that requires a merkle proof. Check out the section [here](./ERC721Drop#creating-a-presale-allow-list) for creating an allowlist. ``` function purchasePresaleWithRewards( uint256 quantity, uint256 maxQuantity, uint256 pricePerToken, bytes32[] calldata merkleProof, string memory comment, address mintReferral ) ```
### Collection Roles ##### Owner The owner doesn't have access to any write functions on the contract. They are only able to set royalty and contract configurations on third-party applications that expect an owner. The owner address is set to the same address as the default admin argument when the contract was created but can be updated to any address by a default admin. ##### Default Admin This admin has the most control and is set when the contract is first initialized. It is recommended to set the deployer address to the default admin when first creating the NFT contract. There can also be more than one default admin and can be updated to a new address. Capabilities include: * Assign and revoke admin roles * Call `adminMint`and `adminMintAirdrop` mint functions * Change the owner Address * Update the `salesConfig` * Call `finalizeOpenEdition` `bytes32 role = 0x0000000000000000000000000000000000000000000000000000000000000000` ##### Minter Role A restricted admin that is only able to access special minting functions such as `adminMint` and `adminMintAirdrop`. `bytes32 role = MINTER_ROLE` ##### Sales Manager Role A restricted admin that is only able to update the `salesConfig` and call the `withdraw` function. `bytes32 role = SALES_MANAGER_ROLE`
### Assigning and Revoking Roles Note, admin roles can only be assigned and revoked by default admins. ##### Checking Admin Status `isAdmin` function checks if an address is an admin or not. ``` function isAdmin(address user) ``` `hasRole` is more granular and checks if an address has a specific admin role. ``` function hasRole(bytes32 role, address account) ``` ##### Granting a Role `grantRole` allows for a default admin to add an admin. ``` function grantRole(bytes32 role, address account) ``` ##### Revoking a Role `revokeRole` allows for a default admin to remove an admin. ``` function revokeRole(bytes32 role, address account) ``` ##### Changing the Owner `setOwner` sets the owner of the contract to a new address. ``` function setOwner(address newOwner) ```
### Withdrawing Funds Once minting has concluded, the funds can be moved out of the contract by calling the `withdraw` function. Withdraw can be called by a default admin, the `fundsRecipient` address, a sales manager role, and the Zora DAO. ``` function withdraw() ``` This will push the funds to the `fundsRecipient` address, which is set to the default admin when the contract was initialized. However, it can be updated to any address by calling the `setFundsRecipient` function. ``` function setFundsRecipient(address payable newRecipientAddress) ```
### Creating a Presale AllowList A Merkle root allows a large data set to be condensed and expressed in a small piece of data. The Merkle root is used to store a list of valid preSale minting addresses, without needing to store the whole list directly in the contract. Here is both an interface and source code that makes it easy to generate a Merkle root and proofs for allowlist minting: * [Generator Interface](https://3e2rz5.sse.codesandbox.io/) * [Lanyard Tool](https://lanyard.org/) It is possible to upload an allowlist using the manage interface on the create website and then access the list of proofs from the [API here](https://allowlist.zora.co/docs#/default/allowlist_allowlist__root__get).
### Updating Contract Info on OpenSea Once the contract is deployed, the address that is set as the owner will need to log in to OpenSea to access and update the contract information.
### Upgrading the Contract Once deployed it is possible to upgrade the NFT contract to have new functionality. Note, that upgrade options are only the ones that are in the [Zora registry](https://github.com/ourzora/zora-drops-contracts/blob/main/src/FactoryUpgradeGate.sol). All upgrades are opt-in and can only be initiated by a default admin. `upgradeTo` allows the NFT contract to upgrade to a new implementation contract to make delegate calls. ``` function upgradeTo(address newImplementation) ``` Similar to `upgradeTo`, `upgradeToAndCall` allows a new implementation contract to be specified, but it also allows for call data to be passed in when updating. ``` function upgradeToAndCall(address newImplementation, bytes data) ``` ## Edition Metadata Renderer ##### Metadata rendering contract for NFTs with all the same media assets This contract is in charge of managing and rendering the metadata for Zora editions. An edition is an NFT collection where all the NFTs share the same media asset (video, image, etc). Whenever a `tokenURI` is called on the NFT contract, the call is forwarded to this contract to get metadata for a specific NFT. View the source contract code [here](https://github.com/ourzora/zora-drops-contracts/blob/main/src/metadata/EditionMetadataRenderer.sol) and the list of deployed contract addresses [here](https://github.com/ourzora/zora-drops-contracts/tree/main/deployments). ### updateMediaURIs Updates the media asset for the edition. * `target`: The contract address to update metadata for * `imageURI`: The new media uri * `animationURI`: The new animation uri The `imageURI` is the resource for the main piece of media and `animationURI` is used for the thumbnail if a video. ``` function updateMediaURIs( address target, string memory imageURI, string memory animationURI ) ``` ### updateDescription Updates the description for the edition. * `target`: The contract address to update the description for * `newDescription`: The new description ``` function updateDescription(address target, string memory newDescription) ``` ## JSONExtensionRegistry This contract is an extension registry for any address or contract owned by another address to reference a theming configuration file on-chain to update their zora.co minting profile. On the UI level, this is also known as the `Personalize` feature - applicable to profile pages, collection and edition pages. This contract is statically deployed at [0xABCDEFEd93200601e1dFe26D6644758801D732E8](https://etherscan.io/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) on the following chains: | chain | address | etherscan | | ------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------- | | zora | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://explorer.zora.energy/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | | zora sepolia | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://sepolia.explorer.zora.energy/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | | optimism | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://optimistic.etherscan.io/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | | base | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://basescan.org/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | | mainnet | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://etherscan.io/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | | sepolia | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://sepolia.etherscan.io/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | | arbitrum | 0xABCDEFEd93200601e1dFe26D6644758801D732E8 | [↗](https://arbiscan.io/address/0xABCDEFEd93200601e1dFe26D6644758801D732E8) | We will deploy on further chains as needed and we use an open CREATE2 bytecode-based deploy scheme where anyone can deploy this hyperstructure to any chain as desired. ### Updating your configuration `function setJSONExtension(address target, string memory uri) external;` Call this function to set the JSON extension for your own address or an owned target address. We lookup ownership first via `AccessControl` then the `owner()` function. ### Reading your configuration `function getJSONExtension(address target) external returns (string memory);` This function gets the latest registered JSON extension file. ### Checking your admin status `function getIsAdmin(address target, address expectedAdmin) external view returns (bool);` For front-ends checking for updates you can use the `getIsAdmin` function to determine if the ad. ### Source View source at [github.com/ourzora/json-extension-registry](https://github.com/ourzora/json-extension-registry/) ## Contract and Token Metadata Contract metadata has the following json schema: ```json twoslash { "name": "{contract name}", "description": "{contract description}", "image": "{contract image}" } ``` Token metadata has the following json schema: ```json twoslash { "name": "{token name}", "description": "{token description}", "image": "{token image ipfs url}", "animation_url": "{token media ipfs url}", "content": { "mime": "{content mime type}", "uri": "{content ipfs uri}" }, "attributes": { "trait_type": "{trait type}", "value": "{trait value}" } } ``` Note that the `image` field should be a mime type starting with `image/`, however, for best rendering support use `png`, `jpg`, or `gif` images. Be aware larger file sizes may have issues rendering but also can display artifacts. It is recommended to test your images first on [testnet](https://testnet.zora.co/) networks and verify the thumbnails and media work. The `content` field supports *any* mime type as the base of the NFT and is optional but for strong rendering support please ensure the `animation_url` field is set with a valid mime type (valid file types are: `gltf, glb, webm, mp3, mp4, m4v, ogv, and ogg along with mp3, wav, oga, and .html`). Contract and token metadata should be pinned to IPFS using a preferred pinning service, and the url when set on a contract or token should be in an ipfs url format, like: `ipfs://{cid}`. More information about pinning and pinning services can be found at [ipfs documentation](https://docs.ipfs.tech/how-to/work-with-pinning-services/#use-a-third-party-pinning-service). Refer to the SDK guide to [contract](/protocol-sdk/metadata/contract-metadata) and [token metadata](/protocol-sdk/metadata/token-metadata) for utilities and sample code to build and pin the json metadata to IPFS. ## Minting ERC-1155 Tokens [View Source Code](https://github.com/ourzora/zora-protocol/blob/main/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L426) ### Zora Mint Fee Zora charges a small fee for minting an NFT. There is no charge to the creator, all the funds from the sales go to the creator. Lastly, the mint fee doesn't apply to admin minted NFT (airdropping). The best way to find the mint fee for a specific contract is to retrieve it from the contract by calling the `mintFee` function. You can read more about the Zora mint fee [here](https://support.zora.co/en/articles/4981037-zora-mint-fees). `function mintFee() external view returns (uint256)` ### Mint Function with Rewards Referring a mint and passing it in as the `mintReferral` will give a reward to the person or platform that refers the mint. View the rewards section for more information. Purchase tokens given a minter contract and minter arguments * `minter`: The minter contract to use * `tokenId`: The token ID to purchase * `quantity`: The quantity of tokens to purchase * `minterArguments`: The arguments to pass to the minter (detail in the minters section) \*The minter arguments are different for each minter contract and are listed in the section. ``` function mint( IMinter1155 minter, uint256 tokenId, uint256 quantity, address[] calldata rewardsRecipients, bytes calldata minterArguments ) external payable nonReentrant { _mint(minter, tokenId, quantity, rewardsRecipients, minterArguments); } ``` ### Minter Strategy Contracts The minting logic for Zora 1155's lives outside of the main 1155 contract. It lives in separate contracts called minters. To mint a token the `mint` function is called on the main 1155 contract and then minter checks if the user should be able to mint. Then the minter tells the main 1155 contract if it should mint or not. * [Minters Code](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-contracts/src/minters) * [Deployed Addresses](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-deployments/addresses) \*Note, that the minter arguments are type `bytes` #### Fixed Price Strategy Mint NFTs for a specific ETH price. `ETH transaction value = ((price + Zora mint fee) * amount)` `minterArguments`: User address to mint to, in bytes \*Note, the payment amount of ETH must be set an override if using wagmi or ethers.js. ##### Getting the Mint Price Calling the `sale` function on the fixed-price minter will return the price for a specific token. `function sale(address tokenContract, uint256 tokenId) ` #### Merkle Proof Strategy Mints tokens based on a merkle tree. `ETH transaction value = ((price + Zora mint fee) * amount)` `minterArguments`: Address to mint to, Max quantity, Price per token, Merkle proof ### Admin Minting Admins can mint NFTs to addresses. These NFTs **do not** incur the Zora mint fee. ``` function adminMint( address recipient, uint256 tokenId, uint256 quantity, bytes memory data ) external onlyAdminOrRole(tokenId, PERMISSION_BIT_MINTER) ``` ``` function adminMintBatch( address recipient, uint256[] memory tokenIds, uint256[] memory quantities, bytes memory data ) public nonReentrant ``` ## ERC-1155 Role Permissions [View Source Code](https://github.com/ourzora/zora-protocol/blob/ba8548a06b3b003dff59bab1c9aa2738255326c3/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L356) ### Admin and Minter Role * `Admin`: Can update sales, airdrop tokens, metadata, and withdraw ETH * `Minter`: Can mint and airdrop tokens ### Assigning Mint Access By giving an address mint access it will be able to mint NFTs from the contract. However, this means different sales strategies can be created for the contract and given access to manage minting. The minter role can be granted at either the contract or token level. The roles are stored at different bit amounts. ``` uint256 PERMISSION_BIT_ADMIN = 2**1; uint256 PERMISSION_BIT_MINTER = 2**2; ``` Note, contract metadata and other settings are stored at tokenId 0. To specify an update for the contract level, tokenId 0 can be used instead of an individual token. ``` uint256 CONTRACT_BASE_ID = 0; ``` ### Checking for Admin or Role The `isAdminOrRole` checks if an address either has a minter role for a token or if they are the admin. Passing in tokenId 0 will return the role for the contract level. ``` function isAdminOrRole( address user, uint256 tokenId, uint256 role // Optional for admin checking ) ``` ### Contract Level Permissions #### Setting the Owner Set the owner of the contract. This function can only be called by the contract admin. Owner is set to the `defaultAdmin` when the contract is created. ``` function setOwner(address newOwner) external onlyAdmin(CONTRACT_BASE_ID) ``` #### Setting a Contract Role For granting permission at the contract level, 0 is passed in as the tokenId Only an admin can add an address as a role. By default, both the Zora minters have the contract level minter role in the contract. ``` function addPermission( uint256 tokenId, // tokenId 0 for contract level address user, uint256 permissionBits ) external onlyAdmin(tokenId) ``` ### Token Level Permissions Add a role to a user for a specific token. ``` function addPermission( uint256 tokenId, address user, uint256 permissionBits ) external onlyAdmin(tokenId) ``` ### Removing a Role Remove a role from a user for a token or the contract (tokenId 0). ``` function removePermission( uint256 tokenId, address user, uint256 permissionBits ) external onlyAdmin(tokenId) ``` ### Updating Royalties Updates the royalty configuration for a token or the contract (tokenId 0). ``` function updateRoyaltiesForToken( uint256 tokenId, RoyaltyConfiguration memory newConfiguration ) ``` * `royaltyBPS`: The royalty amount in basis points for secondary sales. * `royaltyRecipient`: The address that will receive the royalty payments. `Deprecated` `royaltyMintSchedule`: 1/N tokens are minted to the royalty recipient ``` struct RoyaltyConfiguration { uint32 royaltyMintSchedule; uint32 royaltyBPS; address royaltyRecipient; } ``` ## Protocol SDK ##### Get started building with the Zora smart contracts The Protocol SDK makes interacting with the ZORA protocol easier by generating required transactions for our contracts. #### Features 1. Mint existing 1155 NFTs and gasless NFTs 2. Deploy new contracts and create new tokens 3. Creating a token for free (gasless creation) 4. Minting a token that was created for free (bringing it onchain) #### Installation The SDK is written in typescript and can be installed via `npm`, `yarn`, etc. [Source Code](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-sdk) ```ts npm install @zoralabs/protocol-sdk ``` #### Code Examples 1. [Minting an 1155 token](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-sdk#creating-a-mint-from-an-on-chain-contract) 2. [Deploying a new 1155 contract with a token](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-sdk#creating-an-1155-contract) 3. [Minting a token for free (gasless creation)](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-sdk#creating-a-premint) 4. [Bringing a Gasless NFT onchain and minting](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-sdk#executing-a-premint) ## Selling an ERC-1155 token Once a token has been created, it can then be put up for sale. Minter strategy contracts are separate contracts that hold minting logic, but the main 1155 is called for minting. Check out the [minting](./Minting1155) section to learn more about minters. * [Minter Strategy Code](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-contracts/src/minters) * [Addresses](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-deployments/addresses) To create a sale you must use the `callSale` function on the 1155 contract. This will set the sale in the appropriate minter. ``` function callSale( uint256 tokenId, IMinter1155 salesConfig, // Minter Strategy Contract bytes memory data ) ``` The data that is passed into the minter is used to call the `setSale` function. Each minter has a unique salesConfig. ``` function setSale(uint256 tokenId, SalesConfig memory salesConfig) ``` #### Fixed Price Sale Calling `callSale` on an 1155 contract will create a sale for an NFT, but the `FIXED_PRICE_SALE_STRATEGY` address must be specified. The `salesConfig` for a fixed price is structured as follows: ``` struct SalesConfig { uint64 saleStart; uint64 saleEnd; uint64 maxTokensPerAddress; uint96 pricePerToken; // Price in Wei address fundsRecipient; // Where to send the funds } ``` #### Merkle Sale Create a allow list sale with a Merkle proof. Note, the price and the max mint amount per address are specified when creating the Merkle tree. The Merkle sales config is as follows: ``` struct MerkleSaleSettings { uint64 presaleStart; uint64 presaleEnd; address fundsRecipient; bytes32 merkleRoot; } ``` ### Royalty Royalties are set on the main 1155 contract. * `royaltyBPS`: The royalty amount in basis points for secondary sales. * `royaltyRecipient`: The address that will receive the royalty payments. `*Note*: The `royaltyMintSchedule` argument has been deprecated.` ``` struct RoyaltyConfiguration { uint32 royaltyMintSchedule; uint32 royaltyBPS; address royaltyRecipient; } ``` This can be set at both the contract and token level. ``` function updateRoyaltiesForToken( uint256 tokenId, RoyaltyConfiguration memory newConfiguration ) ``` ## ERC-721 NFT Creator > ⚠︎ 721 NFTs can ***only*** be created and managed on the contract and API level but not on the zora.co UI level. This contract is in charge of deploying new NFT contracts. The factory references an `implementation` contract and clones it to give it it's own unique address. View the contract code [here](https://github.com/ourzora/zora-drops-contracts/blob/main/src/ZoraNFTCreatorV1.sol) and the list of deployed addresses [here](https://github.com/ourzora/zora-721-contracts/tree/main/addresses). ### Edition vs Drop This contract can be used to create either `Editions` or `Drops`. * `Editions`: All the NFTs share the same media asset. * `Drops`: All the NFTs have individual pieces of media. Platforms have the ability to earn some of the protocol rewards for helping creators deploy their smart contracts. ### Global Variables * `implementation`: An NFT contract used for cloning. * `editionMetadataRenderer`: A contract for rendering editions metadata. * `dropMetadataRenderer`: A contract for rendering drops. ### Creating an NFT Contract #### createEditionWithReferral Creates a new edition contract with a deterministic address. Note, not all of these fields can be changed after creating the contract. * `name`: Name of the edition contract (cannot be changed) * `symbol`: Symbol of the edition contract (cannot be changed) * `defaultAdmin`: Default admin address (contract sets the owner to this address by default) * `editionSize`: Total size of the edition (number of possible editions) * `royaltyBPS`: BPS amount of royalty (cannot be changed) * `fundsRecipient`: Recipient for sales and royalties * `description`: Metadata: Description of the edition entry * `animationURI`: Metadata: Animation url (optional) of the edition entry * `imageURI`: Metadata: Image url (semi-required) of the edition entry * `createReferral`: Protocol reward for the platform that helped the creator deploy the NFT contract ``` function createEditionWithReferral( string memory name, string memory symbol, uint64 editionSize, uint16 royaltyBPS, address payable fundsRecipient, address defaultAdmin, IERC721Drop.SalesConfiguration memory saleConfig, string memory description, string memory animationURI, string memory imageURI, address createReferral ) ``` #### createDropWithReferral Creates a new drop contract with a deterministic address. Note, not all of these fields can be changed after creating the contract. * `name`: Name for new contract (cannot be changed) * `symbol`: Symbol for new contract (cannot be changed) * `defaultAdmin`: Default admin address (contract sets the owner to this address by default) * `editionSize`: The max size of the media contract allowed * `royaltyBPS`: BPS for on-chain royalties (cannot be changed) * `fundsRecipient`: Recipient for sales and royalties * `metadataURIBase`: URI Base for metadata * `metadataContractURI`: URI for [contract metadata](https://docs.opensea.io/docs/contract-level-metadata) * `createReferral`: Protocol reward for the platform that helped the creator deploy the NFT contract ``` function createDropWithReferral( string memory name, string memory symbol, address defaultAdmin, uint64 editionSize, uint16 royaltyBPS, address payable fundsRecipient, IERC721Drop.SalesConfiguration memory saleConfig, string memory metadataURIBase, string memory metadataContractURI, address createReferral ) ``` ## Zora Timed Sale Strategy The Zora Sale Timed Sale Strategy introduces a new mint fee and [enables a secondary market that is powered by Uniswap V3](https://support.zora.co/en/categories/577345-secondary-market). New tokens minted will have a mint fee of 0.000111 ETH (✧111). Upon calling `setSale()` a sale will be created for the Zora 1155 NFT along with creating an ERC20z token and a Uniswap V3 Pool. After the sale has ended `launchMarket()` will be called to start the secondary market. This will deploy liquidity into the Uniswap V3 pool and enable the buying and selling of ERC20s on the secondary market as a result. ### Fee breakdown | Recipient | Amount | | --------------- | ------------------- | | Creator | 0.0000555 eth (✧55) | | Create Referral | 0.0000111 eth (✧11) | | Mint Referral | 0.0000222 eth (✧22) | | Zora | 0.0000111 eth (✧11) | | Market | 0.0000111 eth (✧11) | The market reward fee of ✧11 per mint is used to bootstrap liquidity for the Uniswap V3 pool. As soon as the secondary market is launched the mint fees earned by the market will be deposited into the pool thus ensuring that there is liquidity as soon as the pool starts. ### Contract Overview The ZoraTimedSaleStrategy contract is used to create a timed sale for a Zora 1155 token. When it is configured for an 1155 contract and token via the `setSale` function, specifying the `saleStart` and `saleEnd` of the sale, it creates a new ERC20z token and corresponding Uniswap V3 pool for a WETH pair with the ERC20z with a 1% fee. To mint an 1155 token, the `mint` function is called on the ZoraTimedSaleStrategy contract with the mint fee of 0.000111 eth x quantity to mint sent with the call. In the `mint` call, 0.0000111 eth x quantity is held in escrow to bootstrap liquidity for the Uniswap V3 pool, the rest is distributed as rewards via the [ProtocolRewards](./rewards) contract, and x quantity of 1155s is minted to the `recipient`. When the sale has ended, the `launchMarket` function can be called to launch the secondary market, which mints ERC20z tokens, wraps the escrowed ETH as WETH, and deposits the WETH and a portion of the minted ERC20z to the Uniswap V3 pool to launch the secondary market. ```solidity contract ZoraTimedSaleStrategyImpl { /// @notice Deprecated - use SalesConfigV2 struct SalesConfig { /// @notice Unix timestamp for the sale start uint64 saleStart; /// @notice Unix timestamp for the sale end uint64 saleEnd; /// @notice The ERC20Z name string name; /// @notice The ERC20Z symbol string symbol; } struct SalesConfigV2 { /// @notice Unix timestamp for the sale start uint64 saleStart; /// @notice The amount of time after the `minimumMarketEth` is reached until the secondary market can be launched uint64 marketCountdown; /// @notice The amount of ETH required to launch a market uint256 minimumMarketEth; /// @notice The ERC20Z name string name; /// @notice The ERC20Z symbol string symbol; } /// @notice Deprecated - use setSaleV2 /// Called by an 1155 collection to set the sale config for a given token /// @dev Additionally creates an ERC20Z and Uniswap V3 pool for the token /// @param tokenId The collection token id to set the sale config for /// @param salesConfig The sale config to set function setSale(uint256 tokenId, SalesConfig calldata salesConfig) external { //... } /// @notice Called by an 1155 collection to set the sale config for a given token /// @dev Additionally creates an ERC20Z and Uniswap V3 pool for the token /// @param tokenId The collection token id to set the sale config for /// @param salesConfig The sale config to set function setSaleV2( uint256 tokenId, SalesConfigV2 calldata salesConfig ) external { //... } /// @notice Called by a collector to mint a token /// @param mintTo The address to mint the token to /// @param quantity The quantity of tokens to mint /// @param collection The address of the 1155 token to mint /// @param tokenId The ID of the token to mint /// @param mintReferral The address of the mint referral /// @param comment The optional mint comment function mint( address mintTo, uint256 quantity, address collection, uint256 tokenId, address mintReferral, string calldata comment ) external payable nonReentrant { //... } /// @notice Called by anyone upon the end of a primary sale to launch the secondary market. /// @param collection The 1155 collection address /// @param tokenId The 1155 token id function launchMarket(address collection, uint256 tokenId) external { //... } } ``` When the liquidity is deposited into the pool to launch the market, the `Royalties` contract is set as the Uniswap LP position owner. When tokens are swapped in the pool, the Royalties contract can earn fees via these positions it holds in the liquidity pools. Creators can withdraw 75% of the 1% fee through the `claim()` or `claimFor()` function on the contract. ```solidity /// @title Royalties /// @notice Manages the royalty distribution for Zora 1155 secondary markets on Uniswap V3 contract Royalties is ERC721Holder { /// @notice Claim royalties for a creator. /// Must be called by the creator reward recipient for the /// corresponding 1155 contract and token. /// @param erc20z ERC20Z address to claim royalties from /// @param recipient The recipient address function claim( address erc20z, address payable recipient ) external nonReentrant { //... } /// @notice Claim royalties for a creator /// @param erc20z ERC20Z address to claim royalties from function claimFor(address erc20z) external nonReentrant { //... } } ``` ### Math The logic for launching the secondary market is designed with a few requirements: * The secondary market starting price should be 0.000111 eth per token * There should be an equal amount of ERC20 to ERC1155 tokens minted/total supply * Each owned ERC1155 should be backed and unwrappable by 1 ERC20, and vice versa. To achieve this, the following logic is used. For the sake of simplicity, one ERC20 represents 10^18 units: * For each 1155 minted, 0.0000111 eth is escrowed to be used to deposit liquidity into the Uniswap V3 pool * When the sale ends and the market is launched, one ERC20 is minted for each 1155 minted. An additional 10% of ERC20 is minted to provide liquidity for the LP position, and the corresponding 10% of 1155s is minted to match the ERC20 total supply. * That 0.0000111 eth x quantity is wrapped in WETH, and the 10% of the ERC20 is deposited with the WETH to create the initial liquidity in the Uniswap V3 pool which results in a price of 0.000111 eth per ERC20. * Since ERC1155 quantities are in whole numbers, all amounts are rounded up when minting additional for launching the market, and the excess erc20 and erc1155 is burned. A mint threshold has been introduced with the v2 sales configuration. A token must receive a minimum of X mints before a countdown of Y time can start. Once Y time has been reached the secondary market will begin. ### Additional Things That Can be Done On the ERC20z contract, the `wrap()` function converts a quantity of Zora 1155 tokens to their corresponding ERC20z tokens. Similarly `unwrap()` converts a quantity of ERC20z tokens back to the corresponding 1155 tokens. Wrapping and unwrapping is 1:1, fractional values are not possible. ### Deployed Deterministic Addresses The `ZoraTimedSaleStrategy` minter and supporting `Royalties` contracts are deployed deterministically to multiple networks: * Deployed to chains: `Zora`, `Base`, `Ethereum Mainnet`, `Optimism`, `Arbitrum One`, `Blast`, `Zora Sepolia`, `Base Sepolia`, `Sepolia` * Zora Timed Sale Strategy on all chains: `0x777777722D078c97c6ad07d9f36801e653E356Ae` * Royalties on all chains: `0x77777771DF91C56c5468746E80DFA8b880f9719F` ### Requirements To use this sale strategy the Zora 1155 contract needs to be at least version 2.12.3 or greater import {RenderAddresses} from '../../components/RenderAddresses'; import {contracts1155} from '@zoralabs/protocol-deployments'; ## Contracts: ### 1155 Contracts: ## Event-based Overview ### 1155 Contracts #### Creating a New Token When a user creates a new token, the parameters expected are maxSupply and URI. maxSupply is the immutable maximum number of NFTs that can be made for this token and the URI is possible to change but the initial URL representing the token. Now that we have both gasless and on-chain minting the token creation event arguments are slightly different to determine the originating user of the mint. Creating new tokens can happen with a call to either [`setupNewToken()`](https://github.com/ourzora/zora-protocol/blob/HEAD/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L260) or [`delegateSetupNewToken()`](https://github.com/ourzora/zora-protocol/blob/f58ee955e6b50c13e90b4cfd72ab4b68dce86fad/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L765) (used by the gasless creation mint flow). Be aware that often creating a new token and minting often occurs in the *same* transaction. It is also possible to setup a new token without a mint event. Any time a new token is setup, this event is emitted. However, the sender field is not the actual creator and is the premint executor contract in a gasless setting. ```solidity emit UpdatedToken(address sender, uint256 tokenId, TokenData { string uri, uint256 maxSupply, }) ``` Read the [subgraph handler](https://github.com/ourzora/zora-creator-subgraph/blob/HEAD/src/ERC1155Mappings/templates/ZoraCreator1155ImplMappings.ts#L403) for this action. The standard 1155 `URI` event is also emitted when the token is setup when provided with: ```solidity event URI(string uri, uint256 tokenId) // Emitted in ZoraCreator1155Impl:306 ``` The `CreatorAttribution` event is emitted only when bringing a token onchain. The creator of the token in this case is the `creator` field of the event. This is part of a [draft ERC standard](https://eips.ethereum.org/EIPS/eip-7015). If necessary, this field can be verified by extracting the signer of the `signature` using `structHash`. ```solidity // this is what attributes this token to have been created by the original creator event CreatorAttribution(bytes32 structHash, string domainName, string version, address creator, bytes signature); // Emitted in `ZoraCreator1155Impl:781` ``` #### Setting a Price ##### Events Emitted: Minting a token can occur via different `SalesConfiguration` contracts which are given `Minter` roles on the 1155 contracts to setup a mint. Sales configurations are linked to contracts via `Permissions` with the `Minter` role. You can determine which contract is a sales configuration contract by their `contractName`. The most common `SalesConfiguration` is a `FixedPriceSaleStrategy`. The `factory` contracts include getters for `fixedPriceMinter` and `merkleMinter` which are the two zora-supported sales methods but users can add their own as well. We index known sales configuration contracts for `SaleSet` events. ```solidity event SaleSet(address indexed mediaContract, uint256 indexed tokenId, SalesConfig { /// @notice Unix timestamp for the sale start uint64 saleStart; /// @notice Unix timestamp for the sale end uint64 saleEnd; /// @notice Max tokens that can be minted for an address, 0 if unlimited uint64 maxTokensPerAddress; /// @notice Price per token in eth wei uint96 pricePerToken; /// @notice Funds recipient (0 if no different funds recipient than the contract global) address fundsRecipient; } salesConfig); ``` ##### How to call: These settings are set via the `callSale` argument which sets the caller context for security purposes to be the calling contract and does the required permissions checks: ```solidity function callSale(uint256 tokenId, IMinter1155 minterModule, bytes calldata data); ``` For example, you would setup a fixed price nft sale in solidity for token id `1` using: ```solidity Zora1155(nftContract).callSale(1, FIXED_PRICE_SALE_STRATEGY, abi.encodeWithSelector(FixedPriceSaleStrategy.setSale(1, SalesConfig({ saleStart: 0, saleEnd: 1735711271, // new years 2025 maxTokensPerAddress: 0, // unlimited pricePerToken: 0 ether, fundsRecipient: address(0) // set to contract })))); ``` Note that the `FIXED_PRICE_SALE_STRATEGY` would need to have `Minter` permissions either on the whole contract (token id `0`) or on the individual token (token id `1`). #### Purchasing / Collecting a Token ##### Mint Events Emitted: When a user purchases a token the primary event emitted is the `Purchased` event: ```solidity event Purchased(address sender, address minterModule, uint256 tokenId, uint256 quantity, uint256 amount); ``` The amount includes both the price and the mint fee. The other events emitted on a purchase are the standard 1155 transfer events: ```solidity event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) ``` If the user wishes to include a `MintComment`, an MintComment event is emitted in the same transaction from the `FixedPriceSaleStrategy`. ```solidity event MintComment(address indexed sender, address indexed tokenContract, uint256 indexed tokenId, uint256 quantity, string comment); ``` ##### Calling the Mint Function: Purchasing a token should be called via: ```solidity function mintWithRewards( IMinter1155 minter, uint256 tokenId, uint256 quantity, bytes calldata minterArguments, address mintReferral ) ``` * The first argument is the minter module which can be found via looking at permissions or the subgraph. * The second argument is the desired `tokenId` and the `quantity`. * Sales information can be found by querying the subgraph or the fixed price minter's `function sale(address tokenContract, uint256 tokenId) returns (SalesConfig memory)`. * MinterArguments for fixed price minter are `abi.encode(address (tokenMintRecipient))`, and `abi.encode(address (tokenMintRecipient), string (mintComment))` if you wish to add a MintComment. * The mintReferral argument is the Zora Rewards referral address. All of these arguments are handled if using the [Protocol SDK](https://docs.zora.co/docs/smart-contracts/creator-tools/ProtocolSDK). #### Mint Comments Mint comments are optional strings emitted on the `FixedPriceSaleStrategy`. Read the [subgraph handler](https://github.com/ourzora/zora-creator-subgraph/blob/HEAD/src/ERC721Mappings/templates/ERC721DropMappings.ts#L344). ```solidity event MintComment(address indexed sender, address indexed tokenContract, uint256 indexed tokenId, uint256 quantity, string comment); ``` #### Permissions When permissions are changed the `UpdatedPermissions` event is emitted. ```solidity event UpdatedPermissions(uint256 indexed tokenId, address indexed user, uint256 indexed permissions); ``` Global permissions are assigned to token id 0, and individual token permissions are assigned to the token. By default, the user that creates a token is given admin permissions on that token. | Permission | Bits | Numeric | Description | | ------------- | ---- | ------- | ------------------------------------------------------------------- | | Admin | 2^1 | 2 | Allows for all functionality and for managing permissions | | Minter | 2^2 | 4 | Allows to mint existing tokens | | Sales | 2^3 | 8 | Allows for updating pricing and sales information | | Metadata | 2^4 | 16 | Allows for updating token metadata and information | | Funds Manager | 2^5 | 32 | Allows for withdrawing funds and setting the funds withdraw address | Permissions can be added via [`addPermission(uint256 tokenId, address user, uint256 permissions)`](https://github.com/ourzora/zora-protocol/blob/HEAD/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L330) and removed via [`function removePermission(uint256 tokenId, address user, uint256 permissionBits)`](https://github.com/ourzora/zora-protocol/blob/HEAD/packages/1155-contracts/src/nft/ZoraCreator1155Impl.sol#L338). View the [subgraph handler](https://github.com/ourzora/zora-creator-subgraph/blob/HEAD/src/ERC1155Mappings/templates/ZoraCreator1155ImplMappings.ts#L118). ### 721 > ##### Note > > 721 NFTs are still supported on the contract and API level. However, 721 NFTs *cannot* be created/updated on the UI level but can still be minted. #### Creating a new Token 721 Contracts share both metadata as either a series of metadata or shared edition metadata. They also have the same sales settings across the contract unlike 1155 tokens. New tokens are created by calling the ZoraNFTCreatorV1 proxy contract. Once the contract is created, if the sale is active users can purchase tokens. We also support a `multicall` pattern with the `setupCalls` argument where the factory is granted temporary admin permissions to execute multiple commands on the contract after deployment allowing for setting additional settings or minting upon deployment. ##### Creating an Edition: ```solidity function createEditionWithReferral( string memory name, string memory symbol, address defaultAdmin, uint64 editionSize, uint16 royaltyBPS, address payable fundsRecipient, bytes[] memory setupCalls, IMetadataRenderer metadataRenderer, bytes memory metadataInitializer, address createReferral ) ``` ##### Creating a Drop: Event Emitted when a drop is created from the factory: ``` event CreatedDrop(address indexed creator, address indexed editionContractAddress, uint256 editionSize) ``` This is emitted by the `ZoraNFTCreatorV1` factory contract. ##### Setting a Price Event emitted with Sales Configuration Setup: ``` event SalesConfigChanged(address indexed changedBy); ``` After this event is emitted, the contract sales information can be queried and stored. See [subgraph implementation](https://github.com/ourzora/zora-creator-subgraph/blob/HEAD/src/ERC721Mappings/templates/ERC721DropMappings.ts#L56). ##### Collecting a Token First, sales information can be retrieved by calling `salesConfig()` on the 721 contract which returns all of the presale (allowlist), and public sale (standard purchase) configuration. After this call, the `function mintWithRewards(address recipient, uint256 quantity, string calldata comment, address mintReferral)` function can be called. The mint fee can be queried from `zoraFeeForAmount(uint256 amount) returns (address, uint256 fee)` which returns the total mint fee for a given amount. The value sent is `pricePerToken * numberOfTokens + mintFee`. This emits: ```solidity event IERC721Drop.Sale( address recipient, uint256 quantity, uint256 pricePerToken, uint256 firstPurchasedTokenId ); ``` and if salesComment is not unset (in solidity, is not an empty string) `''`: ``` event IERC721Drop.MintComment( address sender, // Address sending the mint address tokenContract, // Current NFT contract uint256 tokenId, uint256 quantity, string comment ); ``` ### Protocol Rewards Zora Protocol Rewards power rewards for both the 721 and 1155 contracts. The contracts include a shared solidity library to calculate the fees and call a shared hyperstructure to escrow and store the deposits for users to deposit. This allows us to have the gas savings and security of a model where users retrieve funds from the contract rather than push payments where payments are sent to them while also making it easy for users to retrieve all their rewards in one place. Protocol Reward events for a free and a paid mint vary. Since the logic is in the NFT itself, upgrading the NFT can change the deposit behavior below. This is an example of how our NFT contracts behave for the current version. Users need to opt-into new versions with different fee payment amounts by upgrading. ##### Free Mint The below event is emitted from the ZoraRewards contract when a deposit is received from a free mint: Example Event: ```solidity RewardsDeposit( // This is the address of the token creator address indexed creator, // This is the address of the referral for the token creation address indexed createReferral, // This is the address of the referral of the mint address indexed mintReferral, // This is the address of the user that brought the token onchain address firstMinter, // This is the address of the zora multisig address zora, // This is the address of the smart contract depositing the reward address from, // This is the amount going to the `creator` address above. uint256 creatorReward, // This amount is currently 0.000333 ETH for a free mint // This is the amount going to the `createReferral` address above. // This amount is currently 0.000111 ETH uint256 createReferralReward, // This is the amount going to the `mintReferral` address above. // This amount is currently 0.000111 ETH uint256 mintReferralReward, // This is the amount going to the `firstMinter` address above. // This amount is currently 0.000111 ETH uint256 firstMinterReward, // This is the amount going to the `zora` address above. // This amount is currently 0.000111 ETH uint256 zoraReward ) ``` ##### Paid Mint The below event is emitted from the ZoraRewards contract when a deposit is received from a paid mint: Example Event: ```solidity RewardsDeposit( // This is the address of the token creator address indexed creator, // This is the address of the referral for the token creation address indexed createReferral, // This is the address of the referral of the mint address indexed mintReferral, // This is the address of the user that brought the token onchain address firstMinter, // This is the address of the zora multisig address zora, // This is the address of the smart contract depositing the reward address from, // This is the amount going to the `creator` address above. uint256 creatorReward, // This amount is currently 0 ETH for a paid mint // This is the amount going to the `createReferral` address above. // This amount is currently 0.000222 ETH uint256 createReferralReward, // This is the amount going to the `mintReferral` address above. // This amount is currently 0.000222 ETH uint256 mintReferralReward, // This is the amount going to the `firstMinter` address above. // This amount is currently 0.000111 ETH uint256 firstMinterReward, // This is the amount going to the `zora` address above. // This amount is currently 0.000222 ETH uint256 zoraReward ) ``` ## Factory Addresses The Zora factory proxy has been deployed at a deterministic address on all networks. [View all contract addresses here.](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-deployments/) [1155 Factory Code](https://github.com/ourzora/zora-protocol/blob/main/packages/1155-contracts/src/factory/ZoraCreator1155FactoryImpl.sol) ##### Zora (Chain Id: 7777777) | Type | Address | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://explorer.zora.energy/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://explorer.zora.energy/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0xA2c2A96A232113Dd4993E8b048EEbc3371AE8d85](https://explorer.zora.energy/address/0xA2c2A96A232113Dd4993E8b048EEbc3371AE8d85) | ##### Zora Sepolia (Chain Id: 999999999) | Type | Address | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://sepolia.explorer.zora.energy/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://sepolia.explorer.zora.energy/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x6b28d7C2F8b2C2189e95b89B67886eEb16489a97](https://sepolia.explorer.zora.energy/address/0x6b28d7C2F8b2C2189e95b89B67886eEb16489a97) | ##### Mainnet (Chain Id: 1) | Type | Address | | -------------- | --------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://etherscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://etherscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0xF74B146ce44CC162b601deC3BE331784DB111DC1](https://etherscan.io/address/0xF74B146ce44CC162b601deC3BE331784DB111DC1) | ##### Sepolia (Chain Id: 11155111) | Type | Address | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://sepolia.etherscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://sepolia.etherscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x87cfd516c5ea86e50b950678CA970a8a28de27ac](https://sepolia.etherscan.io/address/0x87cfd516c5ea86e50b950678CA970a8a28de27ac) | ##### Base (Chain Id: 8453) | Type | Address | | -------------- | --------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://basescan.org/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://basescan.org/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x58C3ccB2dcb9384E5AB9111CD1a5DEA916B0f33c](https://basescan.org/address/0x58C3ccB2dcb9384E5AB9111CD1a5DEA916B0f33c) | ##### Base Sepolia (Chain Id: 84532) | Type | Address | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://sepolia.basescan.org/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://sepolia.basescan.org/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0xb0C56317E9cEBc6E0f7A59458a83D0A9ccC3e955](https://sepolia.basescan.org/address/0xb0C56317E9cEBc6E0f7A59458a83D0A9ccC3e955) | ##### Optimism (Chain Id: 10) | Type | Address | | -------------- | -------------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://optimistic.etherscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://optimistic.etherscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x7d1a46c6e614A0091c39E102F2798C27c1fA8892](https://optimistic.etherscan.io/address/0x7d1a46c6e614A0091c39E102F2798C27c1fA8892) | ##### Arbitrum One (Chain Id: 42161) | Type | Address | | -------------- | -------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://arbiscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://arbiscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0xa5f8577cCA2eE9d5577E76385dB1Af51517c76bb](https://arbiscan.io/address/0xa5f8577cCA2eE9d5577E76385dB1Af51517c76bb) | ##### Arbitrum Sepolia (Chain Id: 421614) | Type | Address | | -------------- | ---------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://sepolia.arbiscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://sepolia.arbiscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x765FBfF9E400C55035a1180B78A9CBE12aC25414](https://sepolia.arbiscan.io/address/0x765FBfF9E400C55035a1180B78A9CBE12aC25414) | ##### Blast (Chain Id: 81457) | Type | Address | | -------------- | --------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://blastscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://blastscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x53a85FbD2955EF713AA489Ae0C48523E727a0c07](https://blastscan.io/address/0x53a85FbD2955EF713AA489Ae0C48523E727a0c07) | ##### Blast Sepolia (Chain Id: 168587773) | Type | Address | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | | ERC-1155 | [0x777777C338d93e2C7adf08D102d45CA7CC4Ed021](https://sepolia.blastscan.io/address/0x777777C338d93e2C7adf08D102d45CA7CC4Ed021) | | 1155 Preminter | [0x7777773606e7e46C8Ba8B98C08f5cD218e31d340](https://sepolia.blastscan.io/address/0x7777773606e7e46C8Ba8B98C08f5cD218e31d340) | | ERC-721 | [0x3C1ebcF36Ca9DD9371c9aA99c274e4988906c6E3](https://sepolia.blastscan.io/address/0x3C1ebcF36Ca9DD9371c9aA99c274e4988906c6E3) | ## NFT Contracts Introduction ##### Creator contracts make it easy to deploy and sell an NFT collection These contracts allow anyone to deploy [ERC-1155](https://eips.ethereum.org/EIPS/eip-1155) NFT collections in seconds. In addition, these contracts **provide built-in sales mechanics**, making it easy to both deploy a collection and sell the initial mints. [1155 Contract Code](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-contracts) ### Deployment Addresses [Files are numbered by chainId of the network deployment.](https://github.com/ourzora/zora-protocol/tree/main/packages/1155-deployments/addresses) ### Zora Testnet The [Zora Testnet UI](https://testnet.zora.co) allows you to create, configure and collect NFTs on testnet Sepolia. ## Protocol Rewards ### Introduction At Zora, we are passionate about providing the best experience to create and earn onchain. **Protocol Rewards** is a split of the Zora mint fee allowing: * Creators to monetize their work * Developers to earn from NFT mints and creations they facilitate [Rewards escrow contract code](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-rewards) ### Address Rewards v1.1 is deployed at the same address on all networks. 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B ### Fee Split (Per Mint) ##### Free Mint | Recipient | Amount | | --------------- | ------------- | | Creator | 0.0000555 ETH | | Create Referral | 0.0000111 ETH | | Mint Referral | 0.0000222 ETH | | Zora | 0.0000111 ETH | | Market | 0.0000111 ETH | ##### Paid Mint | Recipient | Amount | | --------------- | ------------------- | | Creator | 100% of token price | | Create Referral | 0.000222 ETH | | Mint Referral | 0.000222 ETH | | First Minter | 0.000111 ETH | | Zora | 0.000222 ETH | ##### ERC20 Mint | Recipient | Amount | | --------------- | --------------------------- | | Creator | 95% of earnings from sales | | Mint Fee | 5% of listed purchase price | | Create Referral | 28.57% of Mint Fee | | Mint Referral | 28.57% of Mint Fee | | First Minter | 14.23% of Mint Fee | | Zora | 28.63% of Mint Fee | **Mint Referral**: The platform that referred a specific mint of an NFT **Create Referral**: The platform that referred the creator to deploy the NFT collection. The creator is determined by the royaltyRecipient of the token followed by the funds recipient of the contract. **First Minter**: Only for premints, this is the first collector to execute the premint. In a non-premint context, this reward is paid out to the creator of the NFT. *Note: For ERC20 Mints, the creator is set as the First Minter and earns First Minter rewards by default.* ### How It Works: Creator 1. Creator selects the **"Free + Rewards"** pricing option when creating their 721 or 1155 NFT 2. Creator specifies a wallet address eligible to claim their rewards 3. Creator opens up their edition for minting -- **that's it!** The creator's total ETH generated from rewards is aggregated into an [escrow contract](https://github.com/ourzora/zora-protocol/blob/main/packages/protocol-rewards/src/ProtocolRewards.sol) and can be withdrawn at any time. ### How It Works: Developer #### Create Referral Reward The create referral reward is paid out to the developer or platform that referred the creator to deploy their NFT collection using Zora's contracts. ##### Creating an ERC-1155 Token with Rewards The `createReferral` address is specified upon token creation. ``` function setupNewTokenWithCreateReferral( string calldata newURI, uint256 maxSupply, address createReferral ) public ``` #### Mint Referral Reward The mint referral reward is paid out to the party that referred the collector to mint an NFT. ##### ERC-1155 Minting with Rewards ``` function mintWithRewards( IMinter1155 minter, uint256 tokenId, uint256 quantity, bytes calldata minterArguments, address mintReferral ) ``` ### Withdrawing Rewards Rewards must be withdrawn from the escrow contract, which the address can be found [in the readme](https://github.com/ourzora/zora-protocol/tree/main/packages/protocol-rewards). ```solidity function withdraw(address to, uint256 amount) external; ``` Withdraw for another address directly. ```solidity function withdrawFor(address to, uint256 amount) external; ``` ```solidity function withdrawWithSig( address from, address to, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) ``` ## Zora 1155 Contracts Changelog ### 2.13.2 #### Patch Changes * [1fd92cc8](https://github.com/ourzora/zora-protocol/commit/1fd92cc8): Add contractName field. ### 2.13.1 #### Patch Changes * [ad707434](https://github.com/ourzora/zora-protocol/commit/ad707434): Updated the 1155 Implementation reduceSupply function to be only allowed to be called by the known `TimedSaleStrategy` address to prevent supply from being reduced in the incorrect matter which would prevent markets from being launched. ### 2.13.0 #### Minor Changes * [737fbef9](https://github.com/ourzora/zora-protocol/commit/737fbef9): Mint fee on the 1155 contract changed to 0.000111 eth ### 2.12.4 #### Patch Changes * [82f63033](https://github.com/ourzora/zora-protocol/commit/82f63033): Remove unused canMintQuantity modifier from 1155 contracts ### 2.12.3 #### Patch Changes * [2fce20f4](https://github.com/ourzora/zora-protocol/commit/2fce20f4): Adding a new getOrCreateFactory function for the 1155 contracts. ### 2.12.2 #### Patch Changes * [cf108bdb](https://github.com/ourzora/zora-protocol/commit/cf108bdb): 1155 mint fee hardcoded to 0.000777 eth ### 2.12.1 #### Patch Changes * [527aa518](https://github.com/ourzora/zora-protocol/commit/527aa518): Move from yarn to pnpm properly pinning deps packages. ### 2.12.0 #### Minor Changes * [0ec838a4](https://github.com/ourzora/zora-protocol/commit/0ec838a4): 1155 contracts have a hardcoded mint fee of 0.000111 ether, and no longer have a fee that is determined by the MintsManager contract #### Patch Changes * [898c84a7](https://github.com/ourzora/zora-protocol/commit/898c84a7): \[chore] Update dependencies and runtime scripts This ensures jobs do not match binary names to make runs less ambigious and also that all deps are accounted for. * [2677c896](https://github.com/ourzora/zora-protocol/commit/2677c896): Add reduceSupply interface check to 1155 ### 2.11.0 #### Minor Changes * [d460e79c](https://github.com/ourzora/zora-protocol/commit/d460e79c): - Introduced a `reduceSupply` function allowing an approved minter or admin to reduce the supply for a given token id. New supply must be less than the current maxSupply, and greater than or equal to the total minted so far. * Removed the deprecated `mintWithRewards` function ### 2.10.1 #### Patch Changes * [368940ba](https://github.com/ourzora/zora-protocol/commit/368940ba): Change removePermission behavior to allow a user to remove their own permission ### 2.10.0 #### Minor Changes * [43a394ab](https://github.com/ourzora/zora-protocol/commit/43a394ab): `ERC20PremintConfig` replaced by a more general purpose `PremintConfigV3`, which instead of having erc20 premint specific properties, as an abi encoded `premintSalesConfig`, that is passed to the function `setPremintSale` on the corresponding minter contract. The new `TokenCreationConfigV3` looks like: ```solidity struct TokenCreationConfigV3 { // Metadata URI for the created token string tokenURI; // Max supply of the created token uint256 maxSupply; // RoyaltyBPS for created tokens. The royalty amount in basis points for secondary sales. uint32 royaltyBPS; // The address that the will receive rewards/funds/royalties. address payoutRecipient; // The address that referred the creation of the token. address createReferral; // The start time of the mint, 0 for immediate. uint64 mintStart; // The address of the minter module. address minter; // The abi encoded data to be passed to the minter to setup the sales config for the premint. bytes premintSalesConfig; } ``` where the `premintSalesConfig` is an abi encoded struct that is passed to the minter's function `setPremintSale`: ```solidity ERC20Minter.PremintSalesConfig memory premintSalesConfig = ERC20Minter.PremintSalesConfig({ currency: address(mockErc20), pricePerToken: 1e18, maxTokensPerAddress: 5000, duration: 1000, payoutRecipient: collector }); // this would be set as the property `premintSalesConfig` in the `TokenCreationConfigV3` bytes memory encodedPremintSalesConfig = abi.encode(premintSalesConfig); ``` Correspondingly, new minters must implement the new interface `ISetPremintSale` to be compatible with the new `TokenCreationConfigV3`: ```solidity interface ISetPremintSale { function setPremintSale( uint256 tokenId, bytes calldata salesConfig ) external; } // example implementation: contract ERC20Minter is ISetPremintSale { struct PremintSalesConfig { address currency; uint256 pricePerToken; uint64 maxTokensPerAddress; uint64 duration; address payoutRecipient; } function buildSalesConfigForPremint( PremintSalesConfig memory config ) public view returns (ERC20Minter.SalesConfig memory) { uint64 saleStart = uint64(block.timestamp); uint64 saleEnd = config.duration == 0 ? type(uint64).max : saleStart + config.duration; return IERC20Minter.SalesConfig({ saleStart: saleStart, saleEnd: saleEnd, maxTokensPerAddress: config.maxTokensPerAddress, pricePerToken: config.pricePerToken, fundsRecipient: config.payoutRecipient, currency: config.currency }); } function toSaleConfig( bytes calldata encodedPremintSalesConfig ) private returns (IERC20Minter.SalesConfig memory) { PremintSalesConfig memory premintSalesConfig = abi.decode( encodedPremintSalesConfig, (PremintSalesConfig) ); return buildSalesConfigForPremint(premintSalesConfig); } mapping(address => mapping(uint256 => IERC20Minter.SalesConfig)) public sale; function setPremintSale( uint256 tokenId, bytes calldata premintSalesConfig ) external override { IERC20Minter.SalesConfig memory salesConfig = toSaleConfig( premintSalesConfig ); sale[msg.sender][tokenId] = salesConfig; } } ``` * [2475a4c9](https://github.com/ourzora/zora-protocol/commit/2475a4c9): Updates to Premint that enables preminting against contracts that were not created via premint, as well as adding collaborators to premint contracts by being able specify an array of additionalAdmins in a premint's contract creation config. ##### No breaking changes These updates are fully backwards compatible; the old functions on the contracts are still intact and will work. Additionally, these updates dont require a new premint config version to be signed; the only thing that could be affected is the deterministic address to be signed against, in the case there are additional contract admins. ##### Ability to add contract-wide additional admins with premint There is a new struct called `ContractWithAdditionalAdminsCreationConfig` that replaces `ContractCreationConfig`. This contains, in addition to the existing fields, a new array `address[] additionalAdmins` - these addresses are added as additional admins when a contract is created by converting each address into a setup action that adds the contract-wide role `PERMISSION_BIT_ADMIN` to that account. ```solidity // new struct: struct ContractWithAdditionalAdminsCreationConfig { // Creator/admin of the created contract. Must match the account that signed the message address contractAdmin; // Metadata URI for the created contract string contractURI; // Name of the created contract string contractName; // additional accounts that will be added as admins // to the contract address[] additionalAdmins; } // existing struct that is replaced: struct ContractCreationConfig { address contractAdmin; string contractURI; string contractName; } ``` Having a list of `additionalAdmins` results in the 1155 contract having a different deterministic address, based on a `salt` made from a hash of the array of `setupActions` that are generated to add those additional accounts as admins. As a result, the creator and additional admins would be signing a message against an address expected to be deterministic with consideration for those additional admins. To get the address in consideration of the new admins, there is a new function on the preminter contract: ```solidity // new function that takes into consideration the additional admins: function getContractWithAdditionalAdminsAddress( ContractWithAdditionalAdminsCreationConfig calldata contractConfig ) public view override returns (address); // existing function can be called if there are no additional admins: function getContractAddress( ContractCreationConfig calldata contractConfig ) public view override returns (address); ``` This should be called to get the expected contract address when there are additional admins. To determine if an address is authorized to create a premint when there are additional admins, there is a new function: ```solidity // new function that takes into consideration the additional admins: function isAuthorizedToCreatePremintWithAdditionalAdmins( address signer, address premintContractConfigContractAdmin, address contractAddress, address[] calldata additionalAdmins ) public view returns (bool isAuthorized); // existing function can be called if there are no additional admins: function isAuthorizedToCreatePremint( address signer, address premintContractConfigContractAdmin, address contractAddress ) public view returns (bool isAuthorized); ``` If any account in those `additionalAdmins`, it is considered authorized and can also sign a premint against the contract address of the original premint, before the contract is created. The collaborator's premint can be brought onchain first, and the original admin will be set as the admin along with all the `additionalAdmins`. ##### New ability to do premints against existing contracts Executing premint against contracts not created via premint can be done with by passing a `premintCollection` argument to the new `premint` function: ```solidity function premint( ContractWithAdditionalAdminsCreationConfig memory contractConfig, address premintCollection, PremintConfigEncoded calldata encodedPremintConfig, bytes calldata signature, uint256 quantityToMint, MintArguments calldata mintArguments, address firstMinter, address signerContract ) external payable returns (uint256 tokenId); ``` This premint collection's address must be a zora creator 1155 contract that already supports premint, which is version 2.0.0 and up. ##### New single shared function for executing a premint, which works with all versions of premint configs In order to avoid having to create one function each for premint v1, v2, and future versions of premint, the new function `premint` takes a struct `PremintConfigEncoded` that contains common properties for premint: `uid`, `version`, and `deleted`, an abi encoded `tokenConfig` and a `premintConfigVersion`; the abi encoded token config can be a `TokenCreationConfigV1`, `TokenCreationConfigV2`, or `TokenCreationConfigV3`. Correspondingly the existing `premintV1/premintV2/premintERC20` functions are deprecated in favor of this new function `premint` that takes a `PremintConfigEncoded` for the premintConfig, and the `contractCreationConfig` as the first argument. If the `premintCollection` parameter is set to a zeroAddress, the function will get or create a contract with an address determined by the contractCreationConfig. This single function works with all versions of premint configs: ```solidity struct PremintConfigEncoded { // Unique id of the token, used to ensure that multiple signatures can't be used to create the same intended token. // only one signature per token id, scoped to the contract hash can be executed. uint32 uid; // Version of this premint, scoped to the uid and contract. Not used for logic in the contract, but used externally to track the newest version uint32 version; // If executing this signature results in preventing any signature with this uid from being minted. bool deleted; // abi encoded token creation config bytes tokenConfig; // hashed premint config version bytes32 premintConfigVersion; } function premint( ContractWithAdditionalAdminsCreationConfig memory contractConfig, address premintCollection, PremintConfigEncoded calldata encodedPremintConfig, bytes calldata signature, uint256 quantityToMint, MintArguments calldata mintArguments, address firstMinter, address signerContract ) external payable returns (uint256 tokenId); ``` `premintV2WithSignerContract` has been removed from the preminter contract to save contract size. ##### 1155 factory's createContractDeterministic resulting address is affected by `setupActions` The FactoryProxy's `createContractDeterministic` function now takes into consideration the `bytes[] calldata setupActions` when creating the contract at the deterministic address. This won't affect contracts that don't have any setup actions, as their address will be the same as it was before. ### 2.9.1 #### Patch Changes * [cd6c6361](https://github.com/ourzora/zora-protocol/commit/cd6c6361): ERC20 Minter V2 Changes: * Adds a flat ETH fee that goes to Zora (currently this fee is 0.000111 ETH but the contract owner can change this fee at any time) * Reward recipients will still receive ERC20 rewards however this percentage can now be changed at any time by the contract owner * Adds an `ERC20MinterConfig` struct which contains `zoraRewardRecipientAddress`, `rewardRecipientPercentage`, and `ethReward` * Zora Reward Recipient Address can now be changed at any time by the contract owner as well * `mint` function is now payable * New functions: * `function ethRewardAmount() external view returns (uint256)` * `function setERC20MinterConfig(ERC20MinterConfig memory config) external` * `function getERC20MinterConfig() external view returns (ERC20MinterConfig memory)` * New events: * `event ERC20MinterConfigSet(ERC20MinterConfig config)` * Removed events: * `event ZoraRewardsRecipientSet(address indexed prevRecipient, address indexed newRecipient)` * `event ERC20MinterInitialized(uint256 rewardPercentage)` ### 2.9.0 #### Minor Changes * 50a4e09: * Zora Creator 1155 contracts use the MINTs contracts to get the mint fee, mint, and redeem a mint ticket upon minting. * `ZoraCreator1155Impl` adds a new method `mintWithMints` that allows for minting with MINTs that are already owned. * 50a4e09: - Zora Creator 1155 contracts no longer have a public facing function `computeFreeMintRewards` and `computePaidMintRewards` * protocol rewards calculation logic has been refactored and moved from the RewardSplits contract to the ZoraCreator1155Impl itself to save on contract size. * remove `ZoraCreator1155Impl.adminMintBatch` to save contract size * 50a4e09: - To support the MINTs contract passing the first minter as an argument to `premintV2WithSignerContract` - we add the field `firstMinter` to `premintV2WithSignerContract`, and then in the 1155 check that the firstMinter argument is not address(0) since it now can be passed in manually. #### ZoraCreator1155Impl rewards splits are percentage based instead of a fixed value. Prior to 2.9.0, rewards were distributed based on a fixed value in ETH per token minted. From 2.9.0 rewards are distributed based on a percentage of the total reward collected for a mint. The following table breaks down the reward splits for both free and paid mints before and after 2.9.0: | Reward Type | Free Mints (Prior to 2.9.0) | Paid Mints (Prior to 2.9.0) | Free Mints (After 2.9.0) | Paid Mints (After 2.9.0) | | ---------------------- | --------------------------- | --------------------------- | ------------------------ | ------------------------ | | Creator Reward | 0.000333 ETH per token | - | 42.8571% of total reward | - | | First Minter Reward | 0.000111 ETH | 0.000111 ETH per token | 14.2285% | 28.5714% of total reward | | Create Referral Reward | 0.000111 ETH | 0.000222 ETH | 14.2285% | 28.5714% | | Mint Referral Reward | 0.000111 ETH | 0.000222 ETH | 14.2285% | 28.5714% | | Zora Platform Reward | 0.000111 ETH | 0.000222 ETH | 14.2285% | 28.5714% | ### 2.8.1 #### Patch Changes * c2a0a2b: Moved dev time dependencies to devDependencies since they are not needed by external users of the package, they are only used for codegen ### 2.8.0 #### Minor Changes * 13a4785: Adds ERC20 Minter contract which enables zora 1155 creator NFTs to be minted with ERC20 tokens #### Patch Changes * 13a4785: Adds first minter reward to ERC20 Minter * 1cf02a4: Add ERC7572 ContractURIUpdated() event for indexing * 079a596: Moved shared functionality into shared-contracts. premintWithSignerContract takes firstMinter as an argument ### 2.8 * 13a4785: Adds ERC20 Minter which allows users to mint NFTs with ERC20 tokens. ### 2.7.3 #### Patch Changes * 52b16aa: Publishing package in format that supports commonjs imports by specifying exports. ### 2.7.2 #### Patch Changes * acf21c0: * `ZoraCreator1155PremintExecutorImpl` and `ZoraCreator1155Impl` support EIP-1271 based signatures for premint token creation, by taking in an extra param indicating the signing contract, and if that parameter is passed, calling a function on that contract address to validate the signature. EIP-1271 is not supported with PremintV1 signatures. * `ZoraCreator1155Impl` splits out `supportsInterface` check for premint related functionality into two separate interfaces to check for, allowing each interface to be updated independently. ### 2.7.1 #### Patch Changes * 8107ffe: Preminter impl disables initializers ### 2.7.0 #### Minor Changes * e990b9d: Remove platform referral from RewardsSplits. Use new signature for 1155 for `mint` which takes an array of reward recipients. #### Patch Changes * Updated dependencies \[e990b9d] * @zoralabs/protocol-rewards\@1.2.3 ### 2.5.4 #### Patch Changes * 7e00197: \* For premintV1 and V2 - mintReferrer has been changed to an array `mintRewardsRecipients` - which the first element in array is `mintReferral`, and second element is `platformReferral`. `platformReferral is not used by the premint contract yet`. ### 2.5.3 #### Patch Changes * d9f3596: For premint - fix bug where fundsRecipient was not set on the fixed price minter. Now it is properly set to the royaltyRecipient/payoutRecipient ### 2.5.2 #### Patch Changes * e4edaac: fixed bug where premint config v2 did not have correct eip-712 domain. fixed bug in CreatorAttribution event where structHash was not included in it ### 2.5.1 #### Patch Changes * 18de283: Fixed setting uid when doing a premint v1 ### 2.5.0 #### Minor Changes * d84721a: # Premint v2 #### New fields on signature Adding a new `PremintConfigV2` struct that can be signed, that now contains a `createReferral`. `ZoraCreator1155PremintExecutor` recognizes new version of the premint config, and still works with the v1 (legacy) version of the `PremintConfig`. Version one of the premint config still works and is still defined in the `PremintConfig` struct. Additional changes included in `PremintConfigV2`: * `tokenConfig.royaltyMintSchedule` has been removed as it is deprecated and no longer recognized by new versions of the 1155 contract * `tokenConfig.royaltyRecipient` has been renamed to `tokenConfig.payoutRecipient` to better reflect the fact that this address is used to receive creator rewards, secondary royalties, and paid mint funds. This is the address that will be set on the `royaltyRecipient` for the created token on the 1155 contract, which is the address that receives creator rewards and secondary royalties for the token, and on the `fundsRecipient` on the ZoraCreatorFixedPriceSaleStrategy contract for the token, which is the address that receives paid mint funds for the token. #### New MintArguments on premint functions, specifying `mintRecipient` and `mintReferral` `mintReferral` and `mintRecipient` are now specified in the premint functions on the `ZoraCreator1155PremintExecutor`, via the `MintArguments mintArguments` param; new `premintV1` and `premintV2` functions take a `MintArguments` struct as an argument which contains `mintRecipient`, defining which account will receive the minted tokens, `mintComment`, and `mintReferral`, defining which account will receive a mintReferral reward, if any. `mintRecipient` must be specified or else it reverts. #### Replacing external signature validation and authorization check with just authorization check `ZoraCreator1155PremintExecutor`'s function `isValidSignature(contractConfig, premintConfig)` is deprecated in favor of: ```solidity isAuthorizedToCreatePremint( address signer, address premintContractConfigContractAdmin, address contractAddress ) public view returns (bool isAuthorized) ``` which instead of validating signatures and checking if the signer is authorized to create premints, just checks if an signer is authorized to create premints on the contract. This offloads signature decoding/validation to calling clients offchain, and reduces needing to create different signatures for this function on the contract for each version of the premint config. It also allows Premints to be validated on contracts that were not created using premints, such as contracts that are upgraded, and contracts created directly via the factory. #### Changes to handling of setting of fundsRecipient Previously the `fundsRecipient` on the fixed priced minters' sales config for the token was set to the signer of the premint. This has been changed to be set to the `payoutRecipient` of the premint config on `PremintConfigV2`, and to the `royaltyRecipient` of the premint config for v1 of the premint config, for 1155 contracts that are to be newly created, and for existing 1155 contracts that are upgraded to the latest version. #### Changes to 1155's `delegateSetupNewToken` `delegateSetupNewToken` on 1155 contract has been updated to now take an abi encoded premint config, premint config version, and send it to an external library to decode the config, the signer, and setup actions. Previously it took a non-encoded PremintConfig. This new change allows this function signature to support multiple versions of a premint config, while offloading decoding of the config and the corresponding setup actions to the external library. This ultimately allows supporting multiple versions of a premint config and corresponding signature without increasing codespace. `PremintConfigV2` are updated to contain `createReferral`, and now look like: ```solidity struct PremintConfigV2 { // The config for the token to be created TokenCreationConfigV2 tokenConfig; // Unique id of the token, used to ensure that multiple signatures can't be used to create the same intended token. // only one signature per token id, scoped to the contract hash can be executed. uint32 uid; // Version of this premint, scoped to the uid and contract. Not used for logic in the contract, but used externally to track the newest version uint32 version; // If executing this signature results in preventing any signature with this uid from being minted. bool deleted; } struct TokenCreationConfigV2 { // Metadata URI for the created token string tokenURI; // Max supply of the created token uint256 maxSupply; // Max tokens that can be minted for an address, 0 if unlimited uint64 maxTokensPerAddress; // Price per token in eth wei. 0 for a free mint. uint96 pricePerToken; // The start time of the mint, 0 for immediate. Prevents signatures from being used until the start time. uint64 mintStart; // The duration of the mint, starting from the first mint of this token. 0 for infinite uint64 mintDuration; // RoyaltyBPS for created tokens. The royalty amount in basis points for secondary sales. uint32 royaltyBPS; // The address that will receive creatorRewards, secondary royalties, and paid mint funds. This is the address that will be set on the `royaltyRecipient` for the created token on the 1155 contract, which is the address that receives creator rewards and secondary royalties for the token, and on the `fundsRecipient` on the ZoraCreatorFixedPriceSaleStrategy contract for the token, which is the address that receives paid mint funds for the token. address payoutRecipient; // Fixed price minter address address fixedPriceMinter; // create referral address createReferral; } ``` `PremintConfig` fields are **the same as they were before, but are treated as a version 1**: ```solidity struct PremintConfig { // The config for the token to be created TokenCreationConfig tokenConfig; // Unique id of the token, used to ensure that multiple signatures can't be used to create the same intended token. // only one signature per token id, scoped to the contract hash can be executed. uint32 uid; // Version of this premint, scoped to the uid and contract. Not used for logic in the contract, but used externally to track the newest version uint32 version; // If executing this signature results in preventing any signature with this uid from being minted. bool deleted; } struct TokenCreationConfig { // Metadata URI for the created token string tokenURI; // Max supply of the created token uint256 maxSupply; // Max tokens that can be minted for an address, 0 if unlimited uint64 maxTokensPerAddress; // Price per token in eth wei. 0 for a free mint. uint96 pricePerToken; // The start time of the mint, 0 for immediate. Prevents signatures from being used until the start time. uint64 mintStart; // The duration of the mint, starting from the first mint of this token. 0 for infinite uint64 mintDuration; // deprecated field; will be ignored. uint32 royaltyMintSchedule; // RoyaltyBPS for created tokens. The royalty amount in basis points for secondary sales. uint32 royaltyBPS; // The address that will receive creatorRewards, secondary royalties, and paid mint funds. This is the address that will be set on the `royaltyRecipient` for the created token on the 1155 contract, which is the address that receives creator rewards and secondary royalties for the token, and on the `fundsRecipient` on the ZoraCreatorFixedPriceSaleStrategy contract for the token, which is the address that receives paid mint funds for the token. address royaltyRecipient; // Fixed price minter address address fixedPriceMinter; } ``` #### Changes to `ZoraCreator1155PremintExecutorImpl`: * new function `premintV1` - takes a `PremintConfig`, and premint v1 signature, and executes a premint, with added functionality of being able to specify mint referral and mint recipient * new function `premintV2` - takes a `PremintConfigV2` signature and executes a premint, with being able to specify mint referral and mint recipient * deprecated function `premint` - call `premintV1` instead * new function ```solidity isAuthorizedToCreatePremint( address signer, address premintContractConfigContractAdmin, address contractAddress ) public view returns (bool isAuthorized) ``` takes a signer, contractConfig.contractAdmin, and 1155 address, and determines if the signer is authorized to sign premints on the given contract. Replaces `isValidSignature` - by putting the burden on clients to first decode the signature, then pass the recovered signer to this function to determine if the signer has premint authorization on the contract. * deprecated function `isValidSignature` - call `isAuthorizedToCreatePremint` instead #### Patch Changes * 885ffa4: Premint executor can still execute premint mints that were created with V1 signatures for `delegateSetupNewToken` * ffb5cb7: Premint - added method getSupportedPremintSignatureVersions(contractAddress) that returns an array of the premint signature versions an 1155 contract supports. If the contract hasn't been created yet, assumes that when it will be created it will support the latest versions of the signatures, so the function returns all versions. * ffb5cb7: Added method `IZoraCreator1155PremintExecutor.supportedPremintSignatureVersions(contractAddress)` that tells what version of the premint signature the contract supports, and added corresponding method `ZoraCreator1155Impl.supportedPremintSignatureVersions()` to fetch supported version. If premint not supported, returns an empty array. * cacb543: Added impl getter to premint executor ### 2.4.1 #### Patch Changes * 63ef7f6: Added missing functions to IZoraCreator1155 ### 2.4.0 #### Minor Changes * 366ac20: Fix broken storage layout by not including an interface on CreatorRoyaltiesControl * e25ac54: ignore nonzero supply royalty schedule ### 2.3.1 #### Patch Changes * e6f61a9: Include all minter and royalty errors in erc1155 and premint executor abis ### 2.3.0 #### Minor Changes * 4afa879: Creator reward recipient can now be defined on a token by token basis. This allows for multiple creators to collaborate on a contract and each to receive rewards for the token they created. The royaltyRecipient storage field is now used to determine the creator reward recipient for each token. If that's not set for a token, it falls back to use the contract wide fundsRecipient. ### 2.1.0 #### Minor Changes * 9495c34: Supply royalties are no longer supported ### 2.0.4 #### Patch Changes * 64da698: Exporting abi ### 2.0.3 #### Patch Changes * d3ddfbb: fix version packages tests ### 2.0.2 #### Patch Changes * 9207e8f: Deployed deterministic proxies and latest versions to mainnet, goerli, base, base goerli, optimism, optimism goerli ### 2.0.1 #### Patch Changes * 35db763: Adding in built artifacts to package ### 2.0.0 #### Major Changes * 82f6506: Premint with Delegated Minting Deterministic Proxy Addresses Premint deployed to zora and zora goerli ### 1.6.1 #### Patch Changes * b83e1b6: Add first minter payouts as chain sponsor ### 1.6.0 #### Minor Changes * 399b8e6: Adds first minter rewards to zora 1155 contracts. * 399b8e6: Added deterministic contract creation from the Zora1155 factory, Preminter, and Upgrade Gate * 399b8e6: Added the PremintExecutor contract, and updated erc1155 to support delegated minting - Add first minter rewards - [Separate upgrade gate into new contract](https://github.com/ourzora/zora-1155-contracts/pull/204) ### 1.5.0 #### Minor Changes * 1bf2d52: Add TokenId to redeemInstructionsHashIsAllowed for Redeem Contracts * a170f1f: - Patches the 1155 `callSale` function to ensure that the token id passed matches the token id encoded in the generic calldata to forward * Updates the redeem minter to v1.1.0 to support b2r per an 1155 token id #### Patch Changes * b1dbb47: Fix types reference for package export * 4cb56d4: - Ensures sales configs can only be updated for the token ids specified * Deprecates support with 'ZoraCreatorRedeemMinterStrategy' v1.0.1 ### 1.4.0 #### Minor Changes * 5b3fafd: Change permission checks for contracts – fix allowing roles that are not admin assigned to tokenid 0 to apply those roles to any token in the contract. * 9f6510d: Add support for rewards * Add new minting functions supporting rewards * Add new "rewards" library ### 1.3.3 #### Patch Changes * 498998f: Added pgn sepolia Added pgn mainnet * cc3b55a: New base mainnet deploy ## Coins SDK Changelog ### 0.0.6 #### Patch Changes * Updated dependencies [23f723dd](https://github.com/ourzora/zora-protocol/commit/23f723dd) * @zoralabs/coins\@0.7.0 ### 0.0.5 #### Patch Changes * [514f8dd4](https://github.com/ourzora/zora-protocol/commit/514f8dd4): Added validation to URI used to create a coin matching a JSON object with URIs ### 0.0.4 #### Patch Changes * [de700d12](https://github.com/ourzora/zora-protocol/commit/de700d12): Updated intermediary types in coins-sdk to better handle nulls * [b08b33ae](https://github.com/ourzora/zora-protocol/commit/b08b33ae): Fix multiple coins get and update types ### 0.0.3 #### Patch Changes * Updated dependencies [b9f717db](https://github.com/ourzora/zora-protocol/commit/b9f717db) * @zoralabs/coins\@0.6.1 ### 0.0.2 #### Patch Changes * [d9eb5a40](https://github.com/ourzora/zora-protocol/commit/d9eb5a40): Initial release ### 0.0.2-sdkalpha.8 #### Patch Changes * Update export pattern for types on queries ### 0.0.2-sdkalpha.7 #### Patch Changes * [8f5d9185](https://github.com/ourzora/zora-protocol/commit/8f5d9185): Fix types and exports ### 0.0.2-sdkalpha.6 #### Patch Changes * Properly export set api key ### 0.0.2-sdkalpha.5 #### Patch Changes * Release API changes ### 0.0.2-sdkalpha.4 #### Patch Changes * [d8cbf6ea](https://github.com/ourzora/zora-protocol/commit/d8cbf6ea): Update coin sdk structure and offchain functions ### 0.0.2-sdkalpha.3 #### Patch Changes * [60568036](https://github.com/ourzora/zora-protocol/commit/60568036): Add offchain data ### 0.0.2-sdkalpha.2 #### Patch Changes * SDK Update ### 0.0.2-sdkalpha.1 #### Patch Changes * Fix package json inclusion ### 0.0.2-sdkalpha.0 #### Patch Changes * [29a34eaf](https://github.com/ourzora/zora-protocol/commit/29a34eaf): Introduce Coins SDK * Updated dependencies [29a34eaf](https://github.com/ourzora/zora-protocol/commit/29a34eaf) * @zoralabs/coins\@0.5.1-sdkalpha.0 ## Coins Changelog ### 0.7.0 #### Minor Changes * [23f723dd](https://github.com/ourzora/zora-protocol/commit/23f723dd): Integrate doppler for liquidity management with uniswap v3 ### 0.7.0-doppler.0 #### Minor Changes * [96ab8907](https://github.com/ourzora/zora-protocol/commit/96ab8907): Integrate doppler for liquidity management with uniswap v3 ### 0.6.1 #### Patch Changes * [b9f717db](https://github.com/ourzora/zora-protocol/commit/b9f717db): Export IUniswapV3Pool interface ### 0.6.0 #### Minor Changes * [55bc4bf3](https://github.com/ourzora/zora-protocol/commit/55bc4bf3): Update WETH tick and use as the minimum ### 0.5.0 #### Minor Changes * [39ffa77c](https://github.com/ourzora/zora-protocol/commit/39ffa77c): Add coin refunds for large sells with little liquidity ### 0.4.0 #### Minor Changes * [e6ee19ce](https://github.com/ourzora/zora-protocol/commit/e6ee19ce): Updated launch rewards - 10m coins for creator; remaining 990m for market ### 0.3.1 #### Patch Changes * [11854bbe](https://github.com/ourzora/zora-protocol/commit/11854bbe): Updated factory impl abi to return coins purchased on deploy ### 0.3.0 #### Minor Changes * [e1a3d68f](https://github.com/ourzora/zora-protocol/commit/e1a3d68f): Refactored coin interface imports ### 0.2.0 #### Minor Changes * [9fa218c9](https://github.com/ourzora/zora-protocol/commit/9fa218c9): - Final events in preparation for V1 release * Updated the starting tick for WETH pools ### 0.1.1 #### Patch Changes * [1e10ac74](https://github.com/ourzora/zora-protocol/commit/1e10ac74): - Fixed coins package visibility * Renamed export to `coinFactory*` ### 0.1.0 #### Minor Changes * [e42eb013](https://github.com/ourzora/zora-protocol/commit/e42eb013): Initial setup ## Cointags Changelog ### 0.1.2 #### Patch Changes * [066c289a](https://github.com/ourzora/zora-protocol/commit/066c289a): Ensure that cointags can only be created with v3 Uniswap pools ### 0.1.1 #### Patch Changes * [5da3d1b0](https://github.com/ourzora/zora-protocol/commit/5da3d1b0): Removed transient storage as it's no longer used * [9ccd40bb](https://github.com/ourzora/zora-protocol/commit/9ccd40bb): Update cointags with erc7201 storage slots for contract variables ### 0.1.0 #### Patch Changes * [1bc855fd](https://github.com/ourzora/zora-protocol/commit/1bc855fd): Don't revert buyburn if transfer to dead address fails * [669c1834](https://github.com/ourzora/zora-protocol/commit/669c1834): Added upgrade gate and upgradeability to the cointag contract * [1bc855fd](https://github.com/ourzora/zora-protocol/commit/1bc855fd): Recover if transferring erc20s to dead addresses reverts * [f2e523f3](https://github.com/ourzora/zora-protocol/commit/f2e523f3): Removed TWAP based slippage protection * [f30466a8](https://github.com/ourzora/zora-protocol/commit/f30466a8): feat: add check to validate one token in the uniswap pool must be WETH * [036b69e8](https://github.com/ourzora/zora-protocol/commit/036b69e8): Allow direct ETH deposits via the receive() - allowing deposit to happen separately from pull() and eth to be deposited by anyone. ### 0.0.2 #### Patch Changes * [dc84793a](https://github.com/ourzora/zora-protocol/commit/dc84793a): * Set TWAP period to be 10 minutes * Safe transfer of WETH in swap callback * Fix burn error handling weth distribution * [9b1bb9d1](https://github.com/ourzora/zora-protocol/commit/9b1bb9d1): Using transient storage variable for isPulling ## @zoralabs/protocol-deployments Changelog ### 0.5.4 #### Patch Changes * [23f723dd](https://github.com/ourzora/zora-protocol/commit/23f723dd): Integrate doppler for liquidity management with uniswap v3 ### 0.5.4-doppler.0 #### Patch Changes * [96ab8907](https://github.com/ourzora/zora-protocol/commit/96ab8907): Integrate doppler for liquidity management with uniswap v3 ### 0.5.3 #### Patch Changes * [70b039ce](https://github.com/ourzora/zora-protocol/commit/70b039ce): Deployed ZoraFactory for coins to deterministic 7777777 addresses on base and base sepolia ### 0.5.2 #### Patch Changes * [ed9f7741](https://github.com/ourzora/zora-protocol/commit/ed9f7741): Updated coin ABI for updated buy/sell return values ### 0.5.1 #### Patch Changes * [11854bbe](https://github.com/ourzora/zora-protocol/commit/11854bbe): Updated factory impl abi to return coins purchased on deploy ### 0.5.0 #### Minor Changes * [e1a3d68f](https://github.com/ourzora/zora-protocol/commit/e1a3d68f): Refactored coin interface imports ### 0.4.2 #### Patch Changes * [1e10ac74](https://github.com/ourzora/zora-protocol/commit/1e10ac74): - Fixed coins package visibility * Renamed export to `coinFactory*` ### 0.4.1 #### Patch Changes * [855112de](https://github.com/ourzora/zora-protocol/commit/855112de): Add initial coins ### 0.4.0 #### Minor Changes * [fc8e86a8](https://github.com/ourzora/zora-protocol/commit/fc8e86a8): - Added Cointags addresses and abis. * Added IUniswapV3Pool ABI. ### 0.3.11 #### Patch Changes * [ff8084fe](https://github.com/ourzora/zora-protocol/commit/ff8084fe): Update implementation contract versions and addresses for erc20z ### 0.3.10 #### Patch Changes * [abbd6333](https://github.com/ourzora/zora-protocol/commit/abbd6333): Added smart wallet factory deployment and abi ### 0.3.9 #### Patch Changes * [4928687d](https://github.com/ourzora/zora-protocol/commit/4928687d): - Include the `Comments` and `CallerAndCommenter` abis and deployed addresses. * Added new exports for Comments contract cross-chain functionality: * Introduced `permitCommentTypedDataDefinition` function to generate typed data for cross-chain permit commenting * Introduced `permitSparkCommentTypedDataDefinition` function to generate typed data for cross-chain permit sparking * Introduced `permitTimedSaleMintAndCommentTypedDataType` to generate typed data for cross-chain permit minting and commenting. * Introduced `permitBuyOnSecondaryAndCommentTypedDataDefinition` function to generate typed data for cross-chain permit buying on secondary and commenting. * Added `sparkValue` helper function to get the value of a Spark ### 0.3.8 #### Patch Changes * [ad707434](https://github.com/ourzora/zora-protocol/commit/ad707434): Updated the 1155 Implementation reduceSupply function to be gated to the `TimedSaleStrategy` constructor argument to ensure markets are launched when desired. * [2e68a87c](https://github.com/ourzora/zora-protocol/commit/2e68a87c): Updated 1155 impl versions and addresses * [17cc9821](https://github.com/ourzora/zora-protocol/commit/17cc9821): Publishing `SponsoredSparksSpender` addresses and abi ### 0.3.7 #### Patch Changes * [c08ec3b3](https://github.com/ourzora/zora-protocol/commit/c08ec3b3): Deployed SponsoredSparksSpender to more chains ### 0.3.6 #### Patch Changes * [d6aa9a00](https://github.com/ourzora/zora-protocol/commit/d6aa9a00): Fixed the minter address for ZoraTimedSaleStrategy to point to the deterministically deployed address with the correct contract version. ### 0.3.5 #### Patch Changes * [4a29c2b9](https://github.com/ourzora/zora-protocol/commit/4a29c2b9): Bump viem to 2.21.21 ### 0.3.4 #### Patch Changes * [66f33bbb](https://github.com/ourzora/zora-protocol/commit/66f33bbb): fix: update secondary swap helper contract address ### 0.3.3 #### Patch Changes * [b885539f](https://github.com/ourzora/zora-protocol/commit/b885539f): Publish weth addresses ### 0.3.2 #### Patch Changes * [247ebc86](https://github.com/ourzora/zora-protocol/commit/247ebc86): update for timed sales v2 * [24520e9a](https://github.com/ourzora/zora-protocol/commit/24520e9a): Fix sdk setSale for v2 params ### 0.3.1 #### Patch Changes * [d221894d](https://github.com/ourzora/zora-protocol/commit/d221894d): Fix royalties contract address. Include secondary swap address * [f94e5f03](https://github.com/ourzora/zora-protocol/commit/f94e5f03): Deployed secondary swap to rest of chains ### 0.3.0 #### Minor Changes * [58f59243](https://github.com/ourzora/zora-protocol/commit/58f59243): Including erc20z contracts in protocol-deployments #### Patch Changes * [b5a7fac4](https://github.com/ourzora/zora-protocol/commit/b5a7fac4): Deployed latest 1155 to base and base sepolia ### 0.2.2 #### Patch Changes * [12909b5b](https://github.com/ourzora/zora-protocol/commit/12909b5b): Export sparks sponsored mints spender abi, address, and typed data definition * [58914a0c](https://github.com/ourzora/zora-protocol/commit/58914a0c): Deployed latest 1155 version to zora mainnet, zora sepolia, sepolia ### 0.2.1 #### Patch Changes * [527aa518](https://github.com/ourzora/zora-protocol/commit/527aa518): Move from yarn to pnpm properly pinning deps packages ### 0.2.0 #### Minor Changes * [0ec838a4](https://github.com/ourzora/zora-protocol/commit/0ec838a4): Publishing Sparks contracts abis and addresses. #### Patch Changes * [898c84a7](https://github.com/ourzora/zora-protocol/commit/898c84a7): \[chore] Update dependencies and runtime scripts This ensures jobs do not match binary names to make runs less ambigious and also that all deps are accounted for. * [e0b5074d](https://github.com/ourzora/zora-protocol/commit/e0b5074d): Updated mainnet 1155 addresses and versions ### 0.1.13 #### Patch Changes * [9cdd81ac](https://github.com/ourzora/zora-protocol/commit/9cdd81ac): Deployed latest version of 1155 contracts, 1155 factory, preminter, and mints manager to: * blast * Optimism mainnet * Base * Arbitrum One * Arbitrum Sepolia * Sepolia ### 0.1.12 #### Patch Changes * [7af9c4db](https://github.com/ourzora/zora-protocol/commit/7af9c4db): Deployed 1155 version 2.9.0 to mainnet, optimism, base, arbitrum one, arbitrum sepolia, blast ### 0.1.11 #### Patch Changes * [399ba552](https://github.com/ourzora/zora-protocol/commit/399ba552): Deployed deterministic proxies to base sepolia. Deployed latest versions to base sepolia. ### 0.1.10 #### Patch Changes * [16deff0c](https://github.com/ourzora/zora-protocol/commit/16deff0c): Moved typed data definitions from `@zoralabs/protocol-sdk` to `@zoralabs/protocol-deployments` ### 0.1.9 #### Patch Changes * [f4641f4b](https://github.com/ourzora/zora-protocol/commit/f4641f4b): Removed dependencies from `zora-1155-contracts`, `1155-deployments`, `mints-contracts`, and `mints-deployments` ### 0.1.8 #### Patch Changes * 8e514b7: Deployed lateset MintsEthUnwrapperAndCaller to chains ### 0.1.7 #### Patch Changes * b6fc3a4: Deployed latest ZoraMintsManagerImpl to zora and zora-sepolia * 5e6a4b0: Added Protocol Rewards and ERC20 Minter abis and addresses to protocol-deployments ### 0.1.6 #### Patch Changes * 9a16b81: Remove graphql-request from hard dependencies in protocol sdk ### 0.1.5 #### Patch Changes * 042edbe: Chain ids in published protocol-deployments package are now numbers instead of strings * 50a4e09: Includes MINTs contracts abis and addresses ### 0.1.4 #### Patch Changes * c2a0a2b: Moved dependencies to devDependencies since they are not needed by external users of the package, they are only used for codegen ### 0.1.3 #### Patch Changes * bb163d3: New preminter impl deployed to mainnet chains ### 0.1.2 #### Patch Changes * 52b16aa: Publishing package in format that supports commonjs imports by specifying exports * Updated dependencies \[52b16aa] * @zoralabs/zora-1155-contracts\@2.7.3 ### 0.1.1 #### Patch Changes * 8d6163c: Deployed to blast & blast sepolia. ### 0.1.0 #### Minor Changes * 653f625: * Configs & addresses bundled in the following format: `contracts{contractName}/addresses|chainConfigs/{chainId}/config` * Including bundled json output for each set of configs/addresses for a contract in the folder `bundled-configs` ### 0.0.14 #### Patch Changes * Added back protocol-deployments - bundling 1155-deployments into it ### 0.0.13 #### Patch Changes * f3332ee: Remove pgn chain configs and addresses * d2085fd: Deployed to Arbitrum One & Arbitrum Sepolia * a51a0cb: Renamed protocol-deployments to 1155-deployments * Updated dependencies \[8107ffe] * @zoralabs/zora-1155-contracts\@2.7.1 ### 0.0.12 #### Patch Changes * 3af77cf: Deploy 2.7.0 to mainnet, zora mainnet, zora sepolia, zora goerli, optimism, base * 23dba1c: Deployed all contracts to sepolia ### 0.0.11 #### Patch Changes * bff853a: Include latest abi in protocol deployments ### 0.0.10 #### Patch Changes * 68c70a9: Tie protocol deployments to v2.5.4 of 1155 * Updated dependencies \[f0c380d] * Updated dependencies \[98e78d7] * Updated dependencies \[050b689] * Updated dependencies \[3f8b18f] * @zoralabs/zora-1155-contracts\@2.6.0 ### 0.0.9 #### Patch Changes * 5156b9e: Deploy latest premint executor to zora sepolia and goerli * Updated dependencies \[7e00197] * @zoralabs/zora-1155-contracts\@2.5.4 ### 0.0.8 #### Patch Changes * 4b77307: Deployed 3.5.3 to zora sepolia and goerli ### 0.0.7 #### Patch Changes * 128b05c: Updated determinstic preminter deployment script to not fail if already deployed * 1d58cd1: Deployed 2.5.2 to zora sepolia and zora goerli * 128b05c: Deployed 2.5.1 to zora sepolia and zora goerli * Updated dependencies \[e4edaac] * @zoralabs/zora-1155-contracts\@2.5.2 ### 0.0.6 #### Patch Changes * f3b7df8: Deployed 2.4.0 with collaborators to zora-goerli, zora-sepolia, base, optimism, mainnet * Updated dependencies \[885ffa4] * Updated dependencies \[ffb5cb7] * Updated dependencies \[ffb5cb7] * Updated dependencies \[d84721a] * Updated dependencies \[cacb543] * @zoralabs/zora-1155-contracts\@2.5.0 ### 0.0.5 #### Patch Changes * 293e2c0: Moved deployment related code from 1155 to protocol-deployments package ### 0.0.4 #### Patch Changes * 6cfb6f9: Add Zora mainnet 1155 v2.3.1 deploy ### 0.0.3 #### Patch Changes * 85bdd23: Update Zora Network addresses to v2.3.0 ### 0.0.2 #### Patch Changes * 4d79b49: Deployed to zora sepolia * b62e471: created new package `protocol-deployments` that includes the deployed contract addresses. * 1155-contracts js no longer exports deployed addresses, just the abis * premint-sdk imports deployed addresses from \`protocol-deployments * 7d1a4c1: Deployed 2.3.0 to zora goerli ### 0.0.2-premint-api.2 #### Patch Changes * c29e080: Update retry and error reporting ### 0.0.2-premint-api.1 #### Patch Changes * 6eaf7bb: add retries ### 0.0.2-premint-api.0 #### Patch Changes * Updated dependencies \[8395b8e] * Updated dependencies \[aae756b] * Updated dependencies \[cf184b3] * @zoralabs/zora-1155-contracts\@2.1.1-premint-api.0 ## @zoralabs/protocol-sdk Changelog ### 0.13.5 #### Patch Changes * Updated dependencies [23f723dd](https://github.com/ourzora/zora-protocol/commit/23f723dd) * @zoralabs/protocol-deployments\@0.5.4 ### 0.13.4 #### Patch Changes * Updated dependencies [70b039ce](https://github.com/ourzora/zora-protocol/commit/70b039ce) * @zoralabs/protocol-deployments\@0.5.3 ### 0.13.3 #### Patch Changes * Updated dependencies [ed9f7741](https://github.com/ourzora/zora-protocol/commit/ed9f7741) * @zoralabs/protocol-deployments\@0.5.2 ### 0.13.2 #### Patch Changes * Updated dependencies [11854bbe](https://github.com/ourzora/zora-protocol/commit/11854bbe) * @zoralabs/protocol-deployments\@0.5.1 ### 0.13.1 #### Patch Changes * Updated dependencies [e1a3d68f](https://github.com/ourzora/zora-protocol/commit/e1a3d68f) * @zoralabs/protocol-deployments\@0.5.0 ### 0.13.0 #### Minor Changes * [cf90efbc](https://github.com/ourzora/zora-protocol/commit/cf90efbc): Remove ability to create and update premints ### 0.12.2 #### Patch Changes * Updated dependencies [1e10ac74](https://github.com/ourzora/zora-protocol/commit/1e10ac74) * @zoralabs/protocol-deployments\@0.4.2 ### 0.12.1 #### Patch Changes * Updated dependencies [855112de](https://github.com/ourzora/zora-protocol/commit/855112de) * @zoralabs/protocol-deployments\@0.4.1 ### 0.12.0 #### Minor Changes * [2a9d2e86](https://github.com/ourzora/zora-protocol/commit/2a9d2e86): Changed how we determine which ERC20Z tokens have secondary royalties by querying the royalties contract directly instead of using the subgraph's secondaryActivated field. BREAKING: The `withdrawRewards` and `getRewardsBalances` functions now require a `publicClient` parameter to query the royalties contract. Update your calls to include the publicClient when using these functions. * [615d81cf](https://github.com/ourzora/zora-protocol/commit/615d81cf): Deprecated createCreatorClient and createCollectorClient in favor of using functions directly ### 0.11.12 #### Patch Changes * Updated dependencies [fc8e86a8](https://github.com/ourzora/zora-protocol/commit/fc8e86a8) * @zoralabs/protocol-deployments\@0.4.0 ### 0.11.11 #### Patch Changes * [ff8084fe](https://github.com/ourzora/zora-protocol/commit/ff8084fe): Updates `minimumMintsForCountdown` and `mintCount` calculations to use the updated 0.0000222 ETH market reward live in v2.2.0 of the timed sale strategy * [2ce16ac7](https://github.com/ourzora/zora-protocol/commit/2ce16ac7): Move from allowlist.zora.co to lanyard.org for allowlist manager service * Updated dependencies [ff8084fe](https://github.com/ourzora/zora-protocol/commit/ff8084fe) * @zoralabs/protocol-deployments\@0.3.11 ### 0.11.10 #### Patch Changes * [a1137e35](https://github.com/ourzora/zora-protocol/commit/a1137e35): saleStart defaults to current timestamp in seconds * Updated dependencies [abbd6333](https://github.com/ourzora/zora-protocol/commit/abbd6333) * @zoralabs/protocol-deployments\@0.3.10 ### 0.11.9 #### Patch Changes * [9d5d1638](https://github.com/ourzora/zora-protocol/commit/9d5d1638): When minting + commenting, and using the timed sale strategy, protocol sdk will call the CallerAndCommenter contract * [088ec6fb](https://github.com/ourzora/zora-protocol/commit/088ec6fb): When buying on secondary, you can now add a comment, which will call the CallerAndCommenter's buyOnSecondaryAndComment function. * Updated dependencies [4928687d](https://github.com/ourzora/zora-protocol/commit/4928687d) * @zoralabs/protocol-deployments\@0.3.9 ### 0.11.8 #### Patch Changes * [330f1131](https://github.com/ourzora/zora-protocol/commit/330f1131): Fix royalties queries to filter by erc20z that have secondary activated ### 0.11.7 #### Patch Changes * [041871d7](https://github.com/ourzora/zora-protocol/commit/041871d7): Fix royalties query for secondary tokens to query subgraph for royaltyRecipient instead of user. ### 0.11.6 #### Patch Changes * Updated dependencies [ad707434](https://github.com/ourzora/zora-protocol/commit/ad707434) * Updated dependencies [2e68a87c](https://github.com/ourzora/zora-protocol/commit/2e68a87c) * Updated dependencies [17cc9821](https://github.com/ourzora/zora-protocol/commit/17cc9821) * @zoralabs/protocol-deployments\@0.3.8 ### 0.11.5 #### Patch Changes * [85d09fa5](https://github.com/ourzora/zora-protocol/commit/85d09fa5): - Adds new fields to `SecondaryInfo` type to expose more information about the secondary market configuration: * `name`: The ERC20Z token name * `symbol`: The ERC20Z token symbol * `saleStart`: Earliest time tokens can be minted * `marketCountdown`: Time after minimum mints reached until secondary market launches * `minimumMintsForCountdown`: Minimum mints required to start countdown * `mintCount`: Total number of tokens minted so far * Deprecates `minimumMarketEth` parameter in favor of `minimumMintsForCountdown` when creating tokens: * `minimumMintsForCountdown` directly specifies minimum number of mints (defaults to `1111`) * `minimumMarketEth` is still supported but calculated internally as `minimumMintsForCountdown * 0.0000111 ETH` * Updated dependencies [c08ec3b3](https://github.com/ourzora/zora-protocol/commit/c08ec3b3) * @zoralabs/protocol-deployments\@0.3.7 ### 0.11.4 #### Patch Changes * Updated dependencies [d6aa9a00](https://github.com/ourzora/zora-protocol/commit/d6aa9a00) * @zoralabs/protocol-deployments\@0.3.6 ### 0.11.3 #### Patch Changes * [364d7906](https://github.com/ourzora/zora-protocol/commit/364d7906): Change DEFAULT\_MINIMUM\_MARKET\_ETH to 0.0123321 eth (1,111 mints) to match default that is set on zora.co * [e68ce881](https://github.com/ourzora/zora-protocol/commit/e68ce881): Fix filtering for active markets * [4a29c2b9](https://github.com/ourzora/zora-protocol/commit/4a29c2b9): Bump viem to 2.21.21 * Updated dependencies [4a29c2b9](https://github.com/ourzora/zora-protocol/commit/4a29c2b9) * @zoralabs/protocol-deployments\@0.3.5 ### 0.11.2 #### Patch Changes * [66f33bbb](https://github.com/ourzora/zora-protocol/commit/66f33bbb): fix: update secondary swap helper contract address * [8d7fdc02](https://github.com/ourzora/zora-protocol/commit/8d7fdc02): For the functions `getToken` and `getTokensOfContract`, the returned `MintableReturn` type has been updated to provide more information about the primary mint status: * Added `primaryMintActive` boolean to indicate if the primary mint is currently active. * Added `primaryMintEnd` optional `bigint` to show the end time of the primary mint, if applicable. * Added `secondaryMarketActive` boolean to indicate if the secondary market is currently active. * Modified `prepareMint` to be conditionally available: * When `primaryMintActive` is `true`, `prepareMint` is available as a `PrepareMint` function. * When `primaryMintActive` is `false`, `prepareMint` is set to `undefined`. This allows for developers to know if the primary mint is active or not, and if not, if they should buy on secondary. * Updated dependencies [66f33bbb](https://github.com/ourzora/zora-protocol/commit/66f33bbb) * @zoralabs/protocol-deployments\@0.3.4 ### 0.11.1 #### Patch Changes * Updated dependencies [b885539f](https://github.com/ourzora/zora-protocol/commit/b885539f) * @zoralabs/protocol-deployments\@0.3.3 ### 0.11.0 #### Minor Changes * [21247473](https://github.com/ourzora/zora-protocol/commit/21247473): Added new functions `buy1155OnSecondary` and `sell1155OnSecondary` to the collector client in the protocol SDK. These functions enable users to buy and sell ERC1155 tokens on the secondary market. Key features include: * Slippage protection for both buying and selling operations * Detailed price breakdowns in wei, sparks, and USDC * Support for specifying recipient addresses * Error handling and simulation parameters ### 0.10.0 #### Minor Changes * [fc4a7f65](https://github.com/ourzora/zora-protocol/commit/fc4a7f65): Support viewing and withdrawing protocol rewards and secondary royalties balances from the sdk, using the new methods `getRewardsBalances` and `withdrawRewards`. ### 0.9.6 #### Patch Changes * [24520e9a](https://github.com/ourzora/zora-protocol/commit/24520e9a): Fix sdk setSale for v2 params * Updated dependencies [247ebc86](https://github.com/ourzora/zora-protocol/commit/247ebc86) * Updated dependencies [24520e9a](https://github.com/ourzora/zora-protocol/commit/24520e9a) * @zoralabs/protocol-deployments\@0.3.2 ### 0.9.5 #### Patch Changes * [879a019a](https://github.com/ourzora/zora-protocol/commit/879a019a): - Fixed types, defaults, and queries for v2 timed sales ### 0.9.4 #### Patch Changes * [b9fcab20](https://github.com/ourzora/zora-protocol/commit/b9fcab20): Removed unneeded async in token setup * Updated dependencies [d221894d](https://github.com/ourzora/zora-protocol/commit/d221894d) * Updated dependencies [f94e5f03](https://github.com/ourzora/zora-protocol/commit/f94e5f03) * Updated dependencies [1b4d5ee7](https://github.com/ourzora/zora-protocol/commit/1b4d5ee7) * @zoralabs/protocol-deployments\@0.3.1 ### 0.9.3 #### Patch Changes * [c75eb65b](https://github.com/ourzora/zora-protocol/commit/c75eb65b): Fix bug where for timed sale strategy, sales settings were not being set. For getting default erc20 name, get it from the contract name instead of fetching from ipfs. ### 0.9.2 #### Patch Changes * [5f964909](https://github.com/ourzora/zora-protocol/commit/5f964909): To speed up performance for `create1155OnExistingContract`, use subgraph to get contract info and reduce quantity of rpc reads. ### 0.9.1 #### Patch Changes * [f40c4a8f](https://github.com/ourzora/zora-protocol/commit/f40c4a8f): `create1155` and `create1155OnExistingContract` return an async `prepareMint` function, enabling to mint right after creating without needing to rely on the subgraph. ### 0.9.0 #### Minor Changes * [8c50a99c](https://github.com/ourzora/zora-protocol/commit/8c50a99c): Add support for creating 1155s and collecting using the new ZoraTimedSaleStrategy. Default to using the new ZoraTimedSaleStrategy as a minter for new 1155s. #### Patch Changes * [47c20f4d](https://github.com/ourzora/zora-protocol/commit/47c20f4d): - Added support for allowlist mint creation and collection * For creating an erc20 mint, the parameter `type` must be set to `erc20Mint` on the `token.salesConfig` object ### 0.8.0 #### Minor Changes * [5417f4dd](https://github.com/ourzora/zora-protocol/commit/5417f4dd): ProtocolSdk `create1155` can only be used for new contracts, and returns the correct deterministic contract address. A new function `create1155OnExistingContract` is added to support creating 1155 tokens on existing contracts ### 0.7.6 #### Patch Changes * Updated dependencies [58f59243](https://github.com/ourzora/zora-protocol/commit/58f59243) * Updated dependencies [b5a7fac4](https://github.com/ourzora/zora-protocol/commit/b5a7fac4) * @zoralabs/protocol-deployments\@0.3.0 ### 0.7.5 #### Patch Changes * [12909b5b](https://github.com/ourzora/zora-protocol/commit/12909b5b): Renamed Mints to Sparks * Updated dependencies [12909b5b](https://github.com/ourzora/zora-protocol/commit/12909b5b) * Updated dependencies [58914a0c](https://github.com/ourzora/zora-protocol/commit/58914a0c) * @zoralabs/protocol-deployments\@0.2.2 ### 0.7.4 #### Patch Changes * [527aa518](https://github.com/ourzora/zora-protocol/commit/527aa518): Move from yarn to pnpm properly pinning deps packages * Updated dependencies [527aa518](https://github.com/ourzora/zora-protocol/commit/527aa518) * @zoralabs/protocol-deployments\@0.2.1 ### 0.7.3 #### Patch Changes * [898c84a7](https://github.com/ourzora/zora-protocol/commit/898c84a7): \[chore] Update dependencies and runtime scripts This ensures jobs do not match binary names to make runs less ambigious and also that all deps are accounted for. * Updated dependencies [898c84a7](https://github.com/ourzora/zora-protocol/commit/898c84a7) * Updated dependencies [0ec838a4](https://github.com/ourzora/zora-protocol/commit/0ec838a4) * Updated dependencies [e0b5074d](https://github.com/ourzora/zora-protocol/commit/e0b5074d) * @zoralabs/protocol-deployments\@0.2.0 ### 0.7.2 #### Patch Changes * [cd5ac235](https://github.com/ourzora/zora-protocol/commit/cd5ac235): protocol sdk gets mint price from the default mint price entity on the subgraph ### 0.7.1 #### Patch Changes * [5c009569](https://github.com/ourzora/zora-protocol/commit/5c009569): Added metadata builder methods to sdk. sdk's method createPremint returns collect/manage urls ### 0.7.0 #### Minor Changes * [f52f28f3](https://github.com/ourzora/zora-protocol/commit/f52f28f3): Added methods to Collector Client: getToken, getTokensOfContract ### 0.6.0 #### Minor Changes * [8c23f05b](https://github.com/ourzora/zora-protocol/commit/8c23f05b): - new high-level sdks: `createCreatorClient` and `createCollectorClient`. `createPremintClient`, `createMintClient`, `create1155CreatorClient`, and `createPremintClient` are removed. * external apis, such as the premint api can be stubbed/replaced/mocked. * new function `mint` on the collector sdk that works with `1155`, `premint`, and `721`s. * `create1155` now supports creating erc20, free, and paid mints. Setup actions now mimic what's on zora.co. #### Patch Changes * [b0f0fb74](https://github.com/ourzora/zora-protocol/commit/b0f0fb74): premintClient - fix default mint duration to be unlimited (it was one week before) ### 0.5.17 #### Patch Changes * [b16078bc](https://github.com/ourzora/zora-protocol/commit/b16078bc): * premintClient now supports creating/minting premints with additional admins. * premint client supports creating premints with just a collection address, as long as the premint has been brought onchain * [502f3295](https://github.com/ourzora/zora-protocol/commit/502f3295): premint sdk - on createPremint, `payoutRecipient` argument moved to `tokenCreationConfig`. premintConfigVersion is no longer an argument; the sdk automatically figures out which is the appropriate version * Updated dependencies [9cdd81ac](https://github.com/ourzora/zora-protocol/commit/9cdd81ac) * @zoralabs/protocol-deployments\@0.1.13 ### 0.5.16 #### Patch Changes * [12387133](https://github.com/ourzora/zora-protocol/commit/12387133): `create1155CreatorClient` requires `chain` to be passed as a default argument instead of a `publicClient` * Updated dependencies [7af9c4db](https://github.com/ourzora/zora-protocol/commit/7af9c4db) * @zoralabs/protocol-deployments\@0.1.12 ### 0.5.15 #### Patch Changes * [888168b8](https://github.com/ourzora/zora-protocol/commit/888168b8): Fix protocol-sdk to point to `isAuthorizedToCreatePremint` * [344f452b](https://github.com/ourzora/zora-protocol/commit/344f452b): Add support for ERC-20 minting on 1155s using ERC20 minters within the function `makePrepareMintTokenParams`. ### 0.5.14 #### Patch Changes * [1a4aa02d](https://github.com/ourzora/zora-protocol/commit/1a4aa02d): Remove graphql-request library and add base sepolia * Updated dependencies [399ba552](https://github.com/ourzora/zora-protocol/commit/399ba552) * @zoralabs/protocol-deployments\@0.1.11 ### 0.5.13 #### Patch Changes * [16deff0c](https://github.com/ourzora/zora-protocol/commit/16deff0c): Moved typed data definitions from protocol-sdk to protocol-deployments * Updated dependencies [16deff0c](https://github.com/ourzora/zora-protocol/commit/16deff0c) * @zoralabs/protocol-deployments\@0.1.10 ### 0.5.12 #### Patch Changes * [e2452f7d](https://github.com/ourzora/zora-protocol/commit/e2452f7d): Removed `zora-1155-contracts`, `1155-deployments`, `mints-contracts`, and `mints-deployments` from devDependencies hierarchy. ### 0.5.11 #### Patch Changes * 8e514b7: Cleanup protocol-sdk to have better docs around all methods, and remove methods that do not need to be exported and are not used. * 598a95b: Bumps protocol-sdk to use viem\@2.x- see the [viem 2.X.X migration guide](https://viem.sh/docs/migration-guide#2xx-breaking-changes) for breaking changes when migratring from viem 1.X.X to 2.X.X * Updated dependencies \[8e514b7] * @zoralabs/protocol-deployments\@0.1.8 ### 0.5.10 #### Patch Changes * Updated dependencies \[9a16b81] * @zoralabs/protocol-deployments\@0.1.6 ### 0.5.9 #### Patch Changes * 825e5f7: Adds optional `createReferral` to `createNew1155Token` params ### 0.5.8 #### Patch Changes * 50a4e09: Added sdk method to get total MINT balance * Updated dependencies \[042edbe] * Updated dependencies \[50a4e09] * @zoralabs/protocol-deployments\@0.1.5 ### 0.5.7 #### Patch Changes * 2eda168: Update default premint version to v2 * 4066420: Adding protocol SDK to base and sepolia networks * Updated dependencies \[bb163d3] * @zoralabs/protocol-deployments\@0.1.3 ### 0.5.6 #### Patch Changes * 52b16aa: Publishing package in format that supports commonjs imports by specifying exports * Updated dependencies \[52b16aa] * @zoralabs/protocol-deployments\@0.1.2 ### 0.5.5 #### Patch Changes * 8a87809: Undo changes to package export because it didn't properly bundle all files in `dist` ### 0.5.4 #### Patch Changes * 9710e5e: Defining exports in protocol-sdk ### 0.5.3 #### Patch Changes * a07499d: Allows an `Account` object to be passed for `signTypedData` compatiblity with Local Accounts ### 0.5.2 #### Patch Changes * 5c536dc: Update optimism eth constant * Updated dependencies \[f3332ee] * Updated dependencies \[d2085fd] * Updated dependencies \[a51a0cb] * @zoralabs/1155-deployments\@0.0.13 ### 0.5.1 #### Patch Changes * 73070c0: * Fix types export - make sure that types are exported to the correct directory. Broken by commit 627f8c37716f0b5c201f75ab1d025ae878be0ae29e7a269d21185fa04e4bcf93 * Exclude tests from built bundle * Fixes #396 ### 0.5.0 #### Minor Changes * a52d245: Fix premint v2 support in premint client and add support for sepolia to SDK: * Fix chain constants config for Zora Goerli. * Support Zora-Sepolia for premint client. * Fix passing of `config_version` to and from the backend API. * Change parameter on `makeMintParameters` from `account` to `minterAccount`. * Fix price minter address for premint client by chain, since it is not the same on all chains (yet). #### Patch Changes * Updated dependencies \[3af77cf] * Updated dependencies \[23dba1c] * @zoralabs/protocol-deployments\@0.0.12 ### 0.4.3 #### Patch Changes * 92b1b0e: Export premint conversions ### 0.4.2 #### Patch Changes * 9b03ed2: Support premint v2 in sdk * Updated dependencies \[bff853a] * @zoralabs/protocol-deployments\@0.0.11 ### 0.4.1 #### Patch Changes * 7e00197: \* For premintV1 and V2 - mintReferrer has been changed to an array `mintRewardsRecipients` - which the first element in array is `mintReferral`, and second element is `platformReferral`. `platformReferral is not used by the premint contract yet`. * 0ceb709: Add mint costs getter for premint to protocol sdk * Updated dependencies \[5156b9e] * @zoralabs/protocol-deployments\@0.0.9 ### 0.4.0 #### Minor Changes * 28884c9: \* `PremintClient` now takes a premint config v1 or v2, and a premint config version, for every call to create/update/delete a premint. PremintClient methods have been simplified and are easier to use - for example `createPremint` no longer allows to specify `deleted` = true. For `makeMintParameters` - it now just takes the uid and contract address (instead of full premint config) * `PremintAPIClient` now converts entities to contract entities before returning them, and correspondingly expects them as contract entities when passed in. It internally converts them to backend entities before sending them to the backend. #### Patch Changes * Updated dependencies \[4b77307] * @zoralabs/protocol-deployments\@0.0.8 ### 0.3.5 #### Patch Changes * 7eb5e3f: ### Changes to `preminter` lower level `preminter.ts` now supports premint v2 by defining v2 typed data defintions. * `isValidSignature` now takes either v1 or v2 of a premint config, along with the premint config version. and both recovers the signer address and validates if the signer can create a premint on the given contract. * new function `premintTypedDataDefinition` which takes a premint config version and returns the signable typed data definition for that version * new function `recoverCreatorFromCreatorAttribution` which recovers the creator address from a `CreatorAttribution` event * new function `supportsPremintVersion` which checks if a given token contract supports a given premint config version * new function `tryRecoverPremintSigner` which takes a premint config version and a premint signature, and tries to recover the signer address from the signature. If the signature is invalid, it returns undefined. #### Changes to PremintClient `PremintClient` creation, updating, and deletion now take both premint config v1 and v2, but currently rejects them until the backend api supports creating v2 premints. * `isValidSignature` now just takes the data directly as a param, instead of `{data}` * 27a2e23: Fix reading the FIXED\_PRICE\_MINTER from the subgraph ### 0.3.4 #### Patch Changes * ea27f01: Fix reading the FIXED\_PRICE\_MINTER from the subgraph ### 0.3.3 #### Patch Changes * 97f58b3: `MintAPIClient` is now a class, that takes a chain id and httpClient in the constructor, enabling the httpClient methods `fetch`, `post`, and `retries` to be overridden. new methods on `MintAPIClient`: `getMintableForToken` - takes a token id and token contract address and returns the mintable for it. Easier to use for fetching specific tokens than `getMintable`. `MintClient` now takes the optional `PublicClient` in the constructor instead of in each function, and stores it or creates a default one if none is provided in the constructor. It also takes an optional `httpClient` param in the constructor, allowing the `fetch`, `post`, and `retries` methods to be overridden when using the api. It now internally creates the MintAPIClient. `MintClient.makePrepareMintTokenParams` has the following changes: * returns a `SimulateContractParams`, instead of an object containing it indexed by key * no longer takes a `PublicClient` as an argument (it should be specified in the constructor instead) new function `MintClient.getMintCosts` takes a mintable and quantity to mint and returns the mintFee, paidMintPrice, and totalCost. * d02484e: premintClient can have http methods overridable via DI, and now takes publicClient and http overrides in `createPremintClient` function. it no longer takes `publicClient` as an argument in functions, and rather uses them from the constructor. `executePremint` has been renamed ot `makeMintParameters` ### 0.3.2 #### Patch Changes * de0b0b7: `preminter` exposes new function isValidSignatureV1 that recovers a signer from a signed premint and determines if that signer is authorized to sign * Updated dependencies \[f3b7df8] * @zoralabs/protocol-deployments\@0.0.6 ### 0.3.1 #### Patch Changes * 92da3ed: Exporting mint client * Updated dependencies \[293e2c0] * @zoralabs/protocol-deployments\@0.0.5 ### 0.3.0 #### Minor Changes * 40e0b32: * rename premint-sdk to protocol-sdk * added minting sdk, usable with `createMintClient` * added 1155 creation sdk, usable with `create1155CreatorClient` * premint sdk is now useable with `createPremintClient` ### 0.1.1 #### Patch Changes * b62e471: created new package `protocol-deployments` that includes the deployed contract addresses. * 1155-contracts js no longer exports deployed addresses, just the abis * premint-sdk imports deployed addresses from \`protocol-deployments * Updated dependencies \[4d79b49] * Updated dependencies \[b62e471] * Updated dependencies \[7d1a4c1] * @zoralabs/protocol-deployments\@0.0.2 ### 0.1.0 #### Minor Changes * 4afa879: Added new premint api that abstracts out calls to the chain signature and submission logic around submitting a premint. This change also incorporates test helpers for premints and introduces docs and an api client for the zora api's premint module. #### Patch Changes * Updated dependencies \[4afa879] * @zoralabs/zora-1155-contracts\@2.3.0 ### 0.0.2-premint-api.2 #### Patch Changes * c29e080: Update retry and error reporting ### 0.0.2-premint-api.1 #### Patch Changes * 6eaf7bb: add retries ### 0.0.2-premint-api.0 #### Patch Changes * Updated dependencies \[8395b8e] * Updated dependencies \[aae756b] * Updated dependencies \[cf184b3] * @zoralabs/zora-1155-contracts\@2.1.1-premint-api.0