Utility

The utility module provides many convenience tools for interacting with the ZDK

The utility functions can be roughly split into 3 categories:

  • Type Constructors

  • Hash Utilities

  • EIP-712 Utilities

Type Constructors

The Zora protocol utilizes a number of structs to encode data as parameters. The ZDK provides some type constructors that can perform some basic validation and return a properly formatted struct.

constructMediaData

  • Accepts the arguments for constructing MediaData type.

  • Validates that the URIs begins with https://.

  • Validates that the hashes are exactly 32 bytes in length.

Name

Type

Description

tokenURI

string

The uri where the media's content can be accessed

metadataURI

string

The uri where the media's metadata can be accessed

contentHash

BytesLike

The sha256 hash of the media's content

metadataHash

BytesLike

The sha256 hash of the media's metadata

const contentHash = await sha256FromBuffer(Buffer.from('some content'))
const metadataHash = await sha256FromBuffer(Buffer.from('some metadata'))
const mediaData = constructMediaData(
'https://token.com',
'https://metadata.com',
contentHash,
metadataHash
)

constructAsk

  • Parses and Validates the currency address to ensure its a valid Ethereum Address

Name

Type

Description

currency

string

The currency address of the Ask

amount

BigNumberish

The amount of the Ask in the currency's atomic units

const dai = '0x6B175474E89094C44Da98b954EedeAC495271d0F'
const decimal100 = Decimal.new(100)
const ask = constructAsk(dai, decimal100.value)

constructBid

  • Parses and Validates the bidder, recipient, and currency addresses.

  • Rounds the SellOnShare to 4 decimals of precision

Name

Type

Description

currency

string

The currency address of the Bid

amount

BigNumberish

The amount of the Bid in the currency's atomic units

bidder

string

The address of the Bid's bidder

recipient

string

The address of the Bid's recipient

sellOnShare

number

The sellOnShare of the Bid

const dai = '0x6B175474E89094C44Da98b954EedeAC495271d0F'
const decimal100 = Decimal.new(100)
const bidder = '0xf13090cC20613BF9b5F0b3E6E83CCAdB5Cd0FbD5'
const bid = constructBid(dai, decimal100.value, bidder, bidder, 33.3333)

constructBidShares

  • Accepts number args, converts them to ethers BigNumber type with 18 decimals of precision.

  • Performs validation that the BigNumber representations sum to 100 in BigNumber form.

Name

Type

Description

creator

number

The creator bidshare for the media

owner

number

The owner bidshare for the media

prevOwner

number

The prevOwner bidshare for the media

const bidShares = constructBidShares(10, 90, 0)

Hashing Utilities

All pieces of media minted on the Zora Protocol must etch a sha256 hash of both its content and metadata onto the blockchain. As such it is important developers interacting with Zora have reliable ways to create and verify hashes of data of all types and sizes.

The majority of NFT protocols don't currently support storing integrity tools like a sha256 checksum. This means that if the URL that other NFTs were to ever change, the NFT would become corrupted with no way to verify the originality of the media. By providing an on-chain integrity check, anyone is able to ensure that a Zora NFT has not been corrupted in any way.

sha256FromBuffer

Create a sha256 from a Buffer object

Name

Type

Description

buffer

Buffer

The Buffer to be hashed

const buf = await fs.readFile('path/to/file')
const hash = sha256FromBuffer(buf)
const otherBuffer = Buffer.from('someContent')
const otherHash = sha256FromBuffer(otherBuffer)

sha256FromHexString

Create a sha256 hash from a hex string. Hex string must be prefixed with 0x

Name

Type

Description

data

string

The hex encoded data to be hashed

const buf = Buffer.from('someContent')
const hexString = '0x'.concat(buf.toString('hex'))
const hash = sha256FromHexString(hexString)

sha256FromFile

Create a sha256 hash from a local file This is most useful for the hashing of large files. It uses a readStream to load bits into memory via a buffer and construct a hash as it consumes the contents of the file.

Name

Type

Description

pathToFile

string

The path to the file to be hashed

chunkSize

number

The chunk size in bytes for the read stream to read into memory

const hash = await sha256FromFile('path/to/file', 16 * 1024)

EIP-712 Utilities

signPermitMessage

Permit was specified as an extension of ERC-20 standard to allow for users to issue approval to accounts without needing ETH.

We have extended it further to be used for the Zora Protocol, so that users can delegate approvals to other smart contracts to perform actions that approved users can do such as:

  • setAsk

  • acceptBid

  • updateContentURI

  • updateMetadataURI

  • transfer

For now, the signer must be an ethers Wallet object. But soon we will support any Signer.

Name

Type

Description

owner

Wallet

The owners's wallet

toAddress

string

The address being granted the permit

mediaId

number

The ID of the media

nonce

number

The permitNonce of the owner address

deadline

number

The deadline of the signature to be included in a tx

domain

EIP712Domain

The EIP712Domain for the permit sig

const provider = new JsonRpcProvider()
const [mainWallet, otherWallet] = generatedWallets(provider)
const rinkebyZora = new Zora(mainWallet, 4)
const deadline = Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 // 24 hours
const domain = rinkebyZora.eip712Domain()
const eipSig = await signPermitMessage(
mainWallet,
otherWallet.address,
0, // mediaId
0, // nonce
deadline,
domain
)

signMintWithSigMessage

We extended EIP-712 to allow for creators to mint without needing ETH. A user can sign a mintWithSig message and use a trusted relayer to relay the transaction and mint on their behalf.

Name

Type

Description

owner

Wallet

The owners's wallet

contentHash

BytesLike

The sha256 hash of the media's content

metadataHash

BytesLike

The sha256 hash of the media's metadata

creatorShareBN

BigNumber

The creator share of the media

nonce

number

The mintWithSigNonce of the owner address

deadline

number

The deadline of the signature to be included in a tx

domain

EIP712Domain

The EIP712Domain for the mintWithSig signature

const provider = new JsonRpcProvider()
const [mainWallet, otherWallet] = generatedWallets(provider)
const rinkebyZora = new Zora(otherWallet, 4)
const contentHash = await sha256FromBuffer(Buffer.from('some content'))
const metadataHash = await sha256FromBuffer(Buffer.from('some metadata'))
const contentURI = 'https://token.com'
const metadataURI = 'https://metadata.com'
const mediaData = constructMediaData(contentURI, metadataURI, contentHash, metadataHash)
const bidShares = constructBidShares(10, 90, 0)
const deadline = Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 // 24 hours
const domain = rinkebyZora.eip712Domain()
const nonce = await rinkebyZora.fetchMintWithSigNonce(mainWallet.address)
const eipSig = await signMintWithSigMessage(
mainWallet,
contentHash,
metadataHash,
Decimal.new(10).value,
nonce.toNumber(),
deadline,
domain
)

recoverSignatureFromPermit

Recover the address of the signing private key of a Permit message

Name

Type

Description

owner

Wallet

The owners's wallet

toAddress

string

The address being granted the permit

mediaId

number

The ID of the media

nonce

number

The permitNonce of the owner address

deadline

number

The deadline of the signature to be included in a tx

domain

EIP712Domain

The EIP712Domain for the permit sig

sig

EIP712Signature

The EIP712Signature to have an address recovered

const provider = new JsonRpcProvider()
const [mainWallet, otherWallet] = generatedWallets(provider)
const zora = new Zora(provider, 4)
const deadline = Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 // 24 hours
const domain = zora.eip712Domain()
const eipSig = await signPermitMessage(
mainWallet,
otherWallet.address,
1,
1,
deadline,
domain
)
const recovered = await recoverSignatureFromPermit(
otherWallet.address,
1,
1,
deadline,
domain,
eipSig
)
if (recovered.toLowerCase() != mainWallet.address.toLowerCase()) {
console.log('Unable to Validate Signature')
} else {
console.log('Signature Validated')
}

recoverSignatureFromMintWithSig

Recover the address of the signing private key of a mintWithSig message

Name

Type

Description

owner

Wallet

The owners's wallet

contentHash

BytesLike

The sha256 hash of the media's content

metadataHash

BytesLike

The sha256 hash of the media's metadata

creatorShareBN

BigNumber

The creator share of the media

nonce

number

The mintWithSigNonce of the owner address

deadline

number

The deadline of the signature to be included in a tx

domain

EIP712Domain

The EIP712Domain for the mintWithSig signature

sig

EIP712Signature

The EIP712Signature to have an address recovered

const provider = new JsonRpcProvider()
const [mainWallet] = generatedWallets(provider)
const rinkebyZora = new Zora(provider, 4)
const deadline = Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 // 24 hours
const domain = rinkebyZora.eip712Domain()
const contentHash = await sha256FromBuffer(Buffer.from('some content'))
const metadataHash = await sha256FromBuffer(Buffer.from('some metadata'))
const eipSig = await signMintWithSigMessage(
mainWallet,
contentHash,
metadataHash,
Decimal.new(10).value,
1,
deadline,
domain
)
const recovered = await recoverSignatureFromMintWithSig(
contentHash,
metadataHash,
Decimal.new(10).value,
2,
deadline,
domain,
eipSig
)
if (recovered.toLowerCase() != mainWallet.address.toLowerCase()) {
console.log('Unable to Validate Signature')
} else {
console.log('Signature Validated')
}