Skip to content

Commit

Permalink
[iain feat] release 1.0.0-rc0 of nft-hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
iainnash committed May 7, 2021
0 parents commit db142e4
Show file tree
Hide file tree
Showing 41 changed files with 15,556 additions and 0 deletions.
76 changes: 76 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
env_defaults: &env_defaults
working_directory: ~
docker:
- image: circleci/node:14.15.1

version: 2.1
jobs:
prepare:
<<: *env_defaults
steps:
- checkout

# Download and cache dependencies
- restore_cache:
keys:
- v1.0-dependencies-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- v1.0-dependencies-

- node/install-packages:
pkg-manager: yarn

- run: yarn install

- run: yarn add jest-junit -W

- save_cache:
paths:
- node_modules
key: v1.0-dependencies-{{ checksum "yarn.lock" }}

- persist_to_workspace:
root: .
paths:
- node_modules

test:
<<: *env_defaults
steps:
- checkout
- attach_workspace:
at: .
- run:
command: yarn run jest --ci --testResultsProcessor="jest-junit" --coverage --coverageDirectory ~/coverage
name: Run Tests
environment:
JEST_JUNIT_OUTPUT_DIR: "~/reports/nft-hooks"
- store_test_results: {path: "~/reports/nft-hooks"}
- store_artifacts: {path: "~/coverage"}
build:
<<: *env_defaults
steps:
- checkout
- attach_workspace:
at: .
- run:
command: yarn run build
name: Build Typescript Package

orbs:
node: circleci/[email protected]
workflows:
test:
jobs:
- prepare:
pre-steps:
- run:
command: echo "registry=https://registry.npmjs.org/" > ~/.npmrc && echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> ~/.npmrc
- build:
requires:
- prepare
- test:
requires:
- build


6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dist/
graph-schemas/*.graphql
yarn-error.log
node_modules/
.DS_Store
.husky
1 change: 1 addition & 0 deletions .husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [1.0.0-rc0] - 2021-05-07

### RC0 Public Release

* Initial public RC release
* Added base 3 hooks to interact with individual NFTs
* Supports Zora auction contracts and zNFTs for the time being
* Normalizes and fetches currency information from Uniswap
* Uses batching and caching for repeatable data requests
* Loads NFT Metadata and Content for each record
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 Zora Labs, Inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## @zoralabs/nft-hooks

Simple React hooks to load Zora NFT data. Includes on-chain data, NFT metadata, and tools for fetching NFT content if needed.

Put together, these power implementations of the zNFT protocol on any website.

This library consists of a data fetch class and associated React hooks to load NFT data is an easy, efficient manner. The API both batches and caches requests, meaning you can use the hooks across a page without needing to worry about significant performance penalties.


Install:
```
yarn add @zoralabs/nft-hooks
```

Then you can import and use the hooks in your react application:

```
import {useNFT, useNFTMetadata} from "@zoralabs/nft-hooks";
function MyNFT() {
const {data} = useNFT("20");
const {metadata} = useNFTMetadata(data && data.metadataURI);
return (
<div>
<h3>{metadata.title}</h3>
<p>{metadata.description}</p>
<p>Owned by: {data.owner.id}</p>
</div>
);
}
```

### All hooks:

| Hook | Usage |
| -- | -- |
| [useNFT](docs/useNFT.md) | Fetches on-chain NFT data |
| [useNFTMetadata](docs/useNFTMetadata.md) | Fetches NFT metadata from a URL |
| [useNFTContent](docs/useNFTContent.md) | Fetches text content from server for rendering from content URL |


### Development:

1. `git clone https://github.com/ourzora/nft-hooks`
2. `cd nft-hooks`
3. `npm i -g yarn` if you don't have yarn installed
4. `yarn`
5. `yarn run test` test your code

Pull requests and tickets are accepted for issues and improvements
to this library.
14 changes: 14 additions & 0 deletions codegen.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"generates": {
"./src/graph-queries/zora-types.d.ts": {
"schema": "./graph-schemas/zora.graphql",
"documents": "./src/graph-queries/zora.ts",
"plugins": ["typescript", "typescript-operations"]
},
"./src/graph-queries/uniswap-types.d.ts": {
"schema": "./graph-schemas/uniswap.graphql",
"documents": "./src/graph-queries/uniswap.ts",
"plugins": ["typescript", "typescript-operations"]
}
}
}
99 changes: 99 additions & 0 deletions docs/useNFT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
This hook fetches data found on the blockchain from the given zNFT. The only argument for the hook is the NFT id. To fetch data for zNFTs on other networks, use the `NFTFetchConfiguration` wrapper component to set the correct network for loading the NFT data.
The main types are within the result `data.nft` object. This object contains the on-chain NFT data itself. The pricing information can be found in `data.pricing` which corresponds to data on-chain for Zora's perpetual zNFT auctions along with the reserve auction functionality.

```ts
import {useNFT} from "@zoralabs/nft-hooks";

type NFTDataType = {
nft: {
id: string, // ID of zNFT
owner: {id: string}, // Address of owner
creator: {id: string}, // Address of creator
metadataURI: string, // URI of metadata for zNFT
metadataHash: string, // sha256 hash for metadata for zNFT
contentURI: string, // URI of content described by metadata
contentHash: string, // sha256 hash of content
},

pricing: {
perpetual: {
bids: { // empty array if no bids
id: string;
createdAtTimestamp: string;
bidder: { id: string };
pricing: PricingInfo;
}[],
ask?: {
id: string,
createdAtTimestamp: string;
pricing: PricingInfo;
};
},
reserve?: {
auctionCurrency: CurrencyInformation;
id: string;
tokenId: string;
status: "Pending" | "Active" | "Canceled" | "Finished";
firstBidTime: string;
duration: string;
expectedEndTimestamp: string;
createdAtTimestamp: string;
finalizedAtTimestamp: string;
},
};

// Current/ongoing auction information synthesized from pricing data
auction: {
highestBid: {
pricing: PricingInfo;
placedBy: string;
placedAt: string;
};
current: {
auctionType: "reserve" | "perpetual";
endingAt?: string;
likelyHasEnded: boolean; // If an auction ended but has not been finalized this will be true.
reserveMet: boolean;
reservePrice?: PricingInfo;
};
};
};

export type PricingInfo = {
currency: CurrencyInformation;
amount: string; // Amount as raw bignumber
prettyAmount: string; // Amount as a normalized BigDecimal value
computedValue?: PricingInfoValue; // Computed value in USD and ETH (available from Uniswap API call)
};

type CurrencyInformation = {
id: string, // Blockchain address of currency. If ETH currency, will be 0x0000000000000000000000000000000000000000
name: string, // Name of currency
symbol: string, // Symbol of currency
decimals: number, // Decimals for currency
};


type useNFT = (id: string) => {
loading: boolean;
error?: string; // undefined if no error, string if error
chainNFT?: NFTDataType; // undefined in error or loading states
}

// Example with usage:
const {chainNFT, loading} = useNFT("2");
```

Alternatively, the same information can be fetched using the base MediaFetchAgentfor server-side or non-react use:

```ts
import {MediaFetchAgent, Networks} from "@zoralabs/nft-hooks";

// Be careful making multiple instances of the fetch agent
// Each instance contains a different request cache.
const fetchAgent = new MediaFetchAgent(Networks.MAINNET);

// Get result from the server
const result = await fetchAgent.loadNFTData("2");
// result type is NFTDataType
```
75 changes: 75 additions & 0 deletions docs/useNFTContent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
This hook makes a request to fetch metadata from IPFS retrieved from the zNFT `metadataURI`.

Most IPFS servers allow remote JSON fetches, including all Zora NFTs.
There is a chance this request could fail when the server does not allow cross-origin requests.
Requests are set with a 15 second timeout to allow showing the user an error message instead of an
indefinite loader.

Hook result type:
```ts
// This is a union type meaning one or another in typescript.
// Use the (media.type) to determine which type was returned from the hook.
type MediaContentType =
| {
uri: string; // URI of content to render, used for media
type: 'uri', // Shows that no content was downloaded, should only render
mimeType: string // mime type string from metadata for rendering
}
| {
text: string; // Text of result
type: 'text', // Shows that text content to render was downloaded
mimeType: string // mime type string from metadata for rendering
};

type useNFTContentType = {
loading: boolean; // If loading from the server
error?: string; // Error returned from network request error or timeout
content?: MediaContentType; // MediaConetentType shown above;
}
```
To use the hook, simply pass in the `contentURI` from the zNFT on-chain data and `mimeType` from the NFT Metadata.
If you do not have access to `mimeType` from the metadata or do not wish to retrieve the metadata, the `mimeType` can be omitted with a small performance impact.
Content returned from this hook is _not_ cached, each time the hook is used the content is fetched.
```ts
import {useNFTContent} from "@zoralabs/nft-hooks";

const MyMediaData = ({uri: string, mimeType: string}) => {
const {error, loading, metadata} = useNFTContent(uri, mimeType);

if (error) {
return <div>Error fetching content</div>;
}

if (loading) {
return <div>loading...</div>;
}

if (content.type === 'text') {
return <div>{content.text}</div>;
}
if (content.mimeType.startsWith("audio")) {
return <audio src={content.uri} />;
}
if (content.mimeType.startsWith("video")) {
return <video src={content.uri} />;
}
if (content.mimeType.startsWith("image")) {
return <img src={content.uri} />;
}
return <div>unknown: {content.mimeType}</div>;
}
```


Alternatively, the same information can be fetched using the base `MediaFetchAgent` for server-side or non-react use:
```ts
import {MediaFetchAgent} from "@zoralabs/nft-hooks";

// Get result from the server
const result = await MediaFetchAgent.fetchContent("https://ipfs.io/ipfs/METADATA_HASH", "application/json");
// result type is MediaContentType
```
Loading

0 comments on commit db142e4

Please sign in to comment.