Skip to content

Commit

Permalink
SDK support for creating / collecting on primary for ZoraTimedSaleStr…
Browse files Browse the repository at this point in the history
…ategy (#663)

* Adds support for creating/minting with the new zora timed sales strategy, only for primary sales
* By default when creating a new token, the sales strategy will be the new timed sales strategy. 
* If token price is set to 0, it will use the new timed sales strategy
* If token price is set to non 0, it uses the fixed priced minter

For erc20z name and symbol, if they are not provided, it gets the name from the token metadata json which it fetches from ipfs, then uses logic extracted from zora-co to convert that to a symbol

It also adds support for stubbing the subgraph queries in tests, which was used for testing out minting after creating using the timed sales strategy

It also includes timed sale strategy errors in the zora1155 abi that is published to protocol-deplooyments, to enable those errors to be decoded by viem

ToDo:
* [x] docs
  • Loading branch information
oveddan authored Aug 7, 2024
1 parent 47c20f4 commit 8c50a99
Show file tree
Hide file tree
Showing 27 changed files with 1,008 additions and 354 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-laws-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/protocol-sdk": minor
---

ProtocolSDK - add support for creating 1155s using the new ZoraTimedSaleStrategy. Default to use the new ZoraTimedSaleStrategy.
57 changes: 53 additions & 4 deletions docs/pages/protocol-sdk/creator/onchain.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,26 @@ Initialize a Creator Client with a chain id and `PublicClient`. The chain is use

```ts twoslash
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { createPublicClient, http } from 'viem';
import { createPublicClient, http, Chain } from 'viem';
import { zora } from "viem/chains";

const publicClient = createPublicClient({
chain: zora,
chain: zora as Chain,
transport: http()
});

const creatorClient = createCreatorClient({ chainId: zora.id, publicClient });
```

### Creating a new 1155 contract and token
### Creating a new 1155 contract and token with Secondary Markets

The function `create1155` is used to create a new 1155 contract and token.
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]
Expand All @@ -42,6 +45,30 @@ that creates an 1155 contract at the deterministic address based on those parame

:::

### 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 set by fetching the json from the `tokenMetadataURI`, and using the `name` property from the token metadata json, 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
Expand Down Expand Up @@ -76,4 +103,26 @@ with the 1155 contract address and the token creation parameters.

:::

### Setting a price per token

A price per token can be optionally set to earn eth additional 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]
```

:::
23 changes: 23 additions & 0 deletions docs/snippets/protocol-sdk/create/createNew1155TokenErc20zName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createCreatorClient } from "@zoralabs/protocol-sdk";
import { publicClient, chainId, creatorAccount } from "./config";

const creatorClient = createCreatorClient({ chainId, publicClient });

const { parameters } = await creatorClient.create1155({
contract: {
name: "testContract",
uri: "ipfs://DUMMY/contract.json",
},
token: {
tokenMetadataURI: "ipfs://DUMMY/token.json",
salesConfig: {
// manually specifying the erc20 name and symbol
erc20Name: "My Token Name", // [!code hl]
erc20Symbol: "MTN", // [!code hl]
},
},
account: creatorAccount,
});

// simulate the transaction
await publicClient.simulateContract(parameters);
46 changes: 46 additions & 0 deletions docs/snippets/protocol-sdk/create/createNew1155WithPrice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
useAccount,
useChainId,
usePublicClient,
useWriteContract,
} from "wagmi";
import { parseEther } from "viem";
import { createCreatorClient } from "@zoralabs/protocol-sdk";

// use wagmi hooks to get the chainId, publicClient, and account
const chainId = useChainId();
const publicClient = usePublicClient()!;
const { address } = useAccount();

const creatorClient = createCreatorClient({ chainId, publicClient });

const { parameters, contractAddress } = await creatorClient.create1155({
// the contract will be created at a deterministic address
contract: {
// contract name
name: "testContract",
// contract metadata uri
uri: "ipfs://DUMMY/contract.json",
},
token: {
tokenMetadataURI: "ipfs://DUMMY/token.json",
salesConfig: {
// setting a price per token on the `salesConfig` will
// result in the token being created with a fixed price in addition
// to the mint fee. In this case, creator rewards will not be earned
// on the mint fee, the `ZoraCreatorFixedPriceSaleStrategy` is setup
// as the minter for this token, and correspondingly the onchain
// secondary market feature will NOT be used for tokens minted using
// that minter.
pricePerToken: parseEther("0.1"), // [!code hl]
},
},
// account to execute the transaction (the creator)
account: address!,
});

const { writeContract } = useWriteContract();

writeContract(parameters);

export { contractAddress };
10 changes: 5 additions & 5 deletions docs/vocs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,7 @@ export default defineConfig({
text: "Creator Client",
items: [
{
text: "create 1155s gaslessly (premints)",
link: "/protocol-sdk/creator/premint",
},
{
text: "create 1155s onchain",
text: "create 1155s",
link: "/protocol-sdk/creator/onchain",
items: [
{
Expand All @@ -147,6 +143,10 @@ export default defineConfig({
},
],
},
{
text: "create 1155s gaslessly (premints)",
link: "/protocol-sdk/creator/premint",
},
],
},
{
Expand Down
13 changes: 11 additions & 2 deletions packages/protocol-deployments-gen/wagmi.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ type Addresses = {
};
};

const timedSaleStrategyErrors = zoraTimedSaleStrategyImplABI.filter(
(x) => x.type === "error",
);

const zora1155Errors = [
...abis.zoraCreator1155ImplABI.filter((x) => x.type === "error"),
...timedSaleStrategyErrors,
];

const get1155Addresses = () => {
const addresses: Addresses = {};

Expand Down Expand Up @@ -97,7 +106,7 @@ const get1155Addresses = () => {
contractName: "ZoraCreator1155FactoryImpl",
chainId,
address: jsonAddress.FACTORY_PROXY,
abi: abis.zoraCreator1155FactoryImplABI,
abi: [...abis.zoraCreator1155FactoryImplABI, ...zora1155Errors],
});
addAddress({
contractName: "ZoraCreatorRedeemMinterFactory",
Expand Down Expand Up @@ -236,7 +245,7 @@ export default defineConfig({
}),
),
{
abi: abis.zoraCreator1155ImplABI,
abi: [...abis.zoraCreator1155ImplABI, ...timedSaleStrategyErrors],
name: "ZoraCreator1155Impl",
},
{
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"vite": "^4.5.0",
"vitest": "^0.34.6"
"vitest": "^2.0.5"
}
}
2 changes: 1 addition & 1 deletion packages/protocol-sdk/src/anvil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const makeAnvilTest = ({
});

export const forkUrls = {
zoraMainnet: "https://rpc.zora.co/",
zoraMainnet: `https://rpc.zora.co/${process.env.VITE_CONDUIT_KEY}`,
zoraGoerli: "https://testnet.rpc.zora.co",
zoraSepolia: "https://sepolia.rpc.zora.energy",
};
Expand Down
38 changes: 38 additions & 0 deletions packages/protocol-sdk/src/apis/subgraph-querier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { IHttpClient } from "./http-api-base";

export interface ISubgraphQuerier {
query: (params: {
subgraphUrl: string;
query: string;
variables?: Record<string, any>;
}) => Promise<object | undefined>;
}

export class SubgraphQuerier implements ISubgraphQuerier {
httpClient: IHttpClient;

constructor(httpClient: IHttpClient) {
this.httpClient = httpClient;
}

async query({
subgraphUrl,
query,
variables,
}: {
subgraphUrl: string;
query: string;
variables?: Record<string, any>;
}) {
const { retries, post } = this.httpClient;

const result = await retries(async () => {
return await post<any>(subgraphUrl, {
query,
variables,
});
});

return result?.data;
}
}
Loading

0 comments on commit 8c50a99

Please sign in to comment.