Added contract helpers for minter, sg721 & whitelist
This commit is contained in:
@@ -1,170 +0,0 @@
|
||||
import { CW721BaseInstance } from './../../../../contracts/cw721/base/contract';
|
||||
import { useCW721BaseContract } from 'contracts/cw721/base'
|
||||
|
||||
export type ExecuteType = typeof EXECUTE_TYPES[number]
|
||||
|
||||
export const EXECUTE_TYPES = [
|
||||
'transfer_nft',
|
||||
'send_nft',
|
||||
'approve',
|
||||
'revoke',
|
||||
'approve_all',
|
||||
'revoke_all',
|
||||
'mint',
|
||||
'burn',
|
||||
] as const
|
||||
|
||||
export interface ExecuteListItem {
|
||||
id: ExecuteType
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export const EXECUTE_LIST: ExecuteListItem[] = [
|
||||
{
|
||||
id: 'transfer_nft',
|
||||
name: 'Transfer NFT',
|
||||
description: `Transfer a token to an address`,
|
||||
},
|
||||
{
|
||||
id: 'send_nft',
|
||||
name: 'Send NFT',
|
||||
description: `Send a token to a contract and execute a message afterwards`,
|
||||
},
|
||||
{
|
||||
id: 'approve',
|
||||
name: 'Approve',
|
||||
description: `Allow an operator to transfer/send a given token from the owner's account`,
|
||||
},
|
||||
{
|
||||
id: 'revoke',
|
||||
name: 'Revoke',
|
||||
description: `Remove permissions of an operator from the owner's account`,
|
||||
},
|
||||
{
|
||||
id: 'approve_all',
|
||||
name: 'Approve All',
|
||||
description: `Allow an operator to transfer/send all tokens from owner's account`,
|
||||
},
|
||||
{
|
||||
id: 'revoke_all',
|
||||
name: 'Revoke All',
|
||||
description: `Remove permissions of an operator from the owner's account`,
|
||||
},
|
||||
{
|
||||
id: 'mint',
|
||||
name: 'Mint',
|
||||
description: `Mint a new token to owner's account`,
|
||||
},
|
||||
{
|
||||
id: 'burn',
|
||||
name: 'Burn',
|
||||
description: `Burn a token transaction sender has access to`,
|
||||
},
|
||||
]
|
||||
|
||||
export interface DispatchExecuteProps {
|
||||
type: ExecuteType
|
||||
[k: string]: unknown
|
||||
}
|
||||
|
||||
type Select<T extends ExecuteType> = T
|
||||
|
||||
/** @see {@link CW721BaseInstance} */
|
||||
export type DispatchExecuteArgs = {
|
||||
contract: string
|
||||
messages?: CW721BaseInstance
|
||||
txSigner: string
|
||||
} & (
|
||||
| { type: undefined }
|
||||
| { type: Select<'transfer_nft'>; recipient: string; tokenId: string }
|
||||
| { type: Select<'send_nft'>; recipient: string; tokenId: string; msg: Record<string, unknown> }
|
||||
| { type: Select<'approve'>; recipient: string; tokenId: string }
|
||||
| { type: Select<'revoke'>; recipient: string; tokenId: string }
|
||||
| { type: Select<'approve_all'>; recipient: string }
|
||||
| { type: Select<'revoke_all'>; recipient: string }
|
||||
| { type: Select<'mint'>; recipient: string; tokenId: string }
|
||||
| { type: Select<'burn'>; tokenId: string }
|
||||
)
|
||||
|
||||
export const dispatchExecute = async (args: DispatchExecuteArgs) => {
|
||||
const { messages } = args
|
||||
if (!messages) {
|
||||
throw new Error('cannot dispatch execute, messages is not defined')
|
||||
}
|
||||
switch (args.type) {
|
||||
case 'transfer_nft': {
|
||||
return messages.transferNft(args.recipient, args.tokenId)
|
||||
}
|
||||
case 'send_nft': {
|
||||
return messages.sendNft(args.contract, args.tokenId, args.msg)
|
||||
}
|
||||
case 'approve': {
|
||||
return messages.approve(args.recipient, args.tokenId)
|
||||
}
|
||||
case 'revoke': {
|
||||
return messages.revoke(args.recipient, args.tokenId)
|
||||
}
|
||||
case 'approve_all': {
|
||||
return messages.approveAll(args.recipient)
|
||||
}
|
||||
case 'revoke_all': {
|
||||
return messages.revokeAll(args.recipient)
|
||||
}
|
||||
case 'mint': {
|
||||
return messages.mint(args.tokenId, args.recipient)
|
||||
}
|
||||
case 'burn': {
|
||||
return messages.burn(args.tokenId)
|
||||
}
|
||||
default: {
|
||||
throw new Error('unknown execute type')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const previewExecutePayload = (args: DispatchExecuteArgs) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { messages } = useCW721BaseContract()
|
||||
switch (args.type) {
|
||||
case 'transfer_nft': {
|
||||
const { contract, recipient, tokenId } = args
|
||||
return messages()?.transferNft(contract, recipient, tokenId)
|
||||
}
|
||||
case 'send_nft': {
|
||||
const { contract, recipient, tokenId, msg } = args
|
||||
return messages()?.sendNft(contract, recipient, tokenId, msg)
|
||||
}
|
||||
case 'approve': {
|
||||
const { contract, recipient, tokenId } = args
|
||||
return messages()?.approve(contract, recipient, tokenId)
|
||||
}
|
||||
case 'revoke': {
|
||||
const { contract, recipient, tokenId } = args
|
||||
return messages()?.revoke(contract, recipient, tokenId)
|
||||
}
|
||||
case 'approve_all': {
|
||||
const { contract, recipient } = args
|
||||
return messages()?.approveAll(contract, recipient)
|
||||
}
|
||||
case 'revoke_all': {
|
||||
const { contract, recipient } = args
|
||||
return messages()?.revokeAll(contract, recipient)
|
||||
}
|
||||
case 'mint': {
|
||||
const { contract, recipient, tokenId } = args
|
||||
return messages()?.mint(contract, tokenId, recipient)
|
||||
}
|
||||
case 'burn': {
|
||||
const { contract, tokenId } = args
|
||||
return messages()?.burn(contract, tokenId)
|
||||
}
|
||||
default: {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const isEitherType = <T extends ExecuteType>(type: unknown, arr: T[]): type is T => {
|
||||
return arr.some((val) => type === val)
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import type { CW721BaseInstance } from 'contracts/cw721/base'
|
||||
|
||||
export type QueryType = typeof QUERY_TYPES[number]
|
||||
|
||||
export const QUERY_TYPES = [
|
||||
'owner_of',
|
||||
'approval',
|
||||
'approvals',
|
||||
'all_operators',
|
||||
'num_tokens',
|
||||
'contract_info',
|
||||
'nft_info',
|
||||
'all_nft_info',
|
||||
'tokens',
|
||||
'all_tokens',
|
||||
'minter',
|
||||
] as const
|
||||
|
||||
export interface QueryListItem {
|
||||
id: QueryType
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export const QUERY_LIST: QueryListItem[] = [
|
||||
{ id: 'owner_of', name: 'Owner Of', description: 'View current owner of given token' },
|
||||
{ id: 'approval', name: 'Approval', description: 'View address that has access to given token' },
|
||||
{ id: 'approvals', name: 'Approvals', description: 'View all approvals of a given token' },
|
||||
{
|
||||
id: 'all_operators',
|
||||
name: 'All Operators',
|
||||
description: "List all the operators that has access all of the owner's tokens",
|
||||
},
|
||||
{ id: 'num_tokens', name: 'Number of Tokens', description: 'View total number of tokens minted' },
|
||||
{ id: 'contract_info', name: 'Contract Info', description: 'View top-level metadata of contract' },
|
||||
{ id: 'nft_info', name: 'NFT Info', description: 'View metadata of a given token' },
|
||||
{ id: 'all_nft_info', name: 'All NFT Info', description: 'View metadata and owner info of a given token' },
|
||||
{ id: 'tokens', name: 'Tokens', description: 'View all the tokens owned by given address' },
|
||||
{ id: 'all_tokens', name: 'All Tokens', description: 'List all the tokens controlled by the contract' },
|
||||
{ id: 'minter', name: 'Minter', description: 'View current minter of the contract' },
|
||||
]
|
||||
|
||||
export interface DispatchQueryProps {
|
||||
ownerAddress: string
|
||||
tokenId: string
|
||||
messages: CW721BaseInstance | undefined
|
||||
type: QueryType
|
||||
}
|
||||
|
||||
export const dispatchQuery = async (props: DispatchQueryProps) => {
|
||||
const { ownerAddress, tokenId, messages, type } = props
|
||||
switch (type) {
|
||||
case 'owner_of': {
|
||||
return messages?.ownerOf(tokenId)
|
||||
}
|
||||
case 'approval': {
|
||||
return messages?.approval(tokenId, ownerAddress)
|
||||
}
|
||||
case 'approvals': {
|
||||
return messages?.approvals(tokenId)
|
||||
}
|
||||
case 'all_operators': {
|
||||
return messages?.allOperators(ownerAddress)
|
||||
}
|
||||
case 'num_tokens': {
|
||||
return messages?.numTokens()
|
||||
}
|
||||
case 'contract_info': {
|
||||
return messages?.contractInfo()
|
||||
}
|
||||
case 'nft_info': {
|
||||
return messages?.nftInfo(tokenId)
|
||||
}
|
||||
case 'all_nft_info': {
|
||||
return messages?.allNftInfo(tokenId)
|
||||
}
|
||||
case 'tokens': {
|
||||
return messages?.tokens(ownerAddress)
|
||||
}
|
||||
case 'all_tokens': {
|
||||
return messages?.allTokens()
|
||||
}
|
||||
case 'minter': {
|
||||
return messages?.minter()
|
||||
}
|
||||
default: {
|
||||
throw new Error('unknown query type')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
export const checkFiles = (images: string[], metadata: string[]) => {
|
||||
// Check images length is equal to metadata length
|
||||
if (images.length !== metadata.length) {
|
||||
throw Error('Images files must have matching number of metadata files')
|
||||
}
|
||||
|
||||
function parseFileName(path: string | null): number {
|
||||
// Check file name is not null
|
||||
if (!path) {
|
||||
throw Error('File cannot be null')
|
||||
}
|
||||
|
||||
// Extract fileName from path
|
||||
const fileName = path.match(
|
||||
/([a-zA-Z0-9\s_\\.\-:]+)(.png|.jpg|.gif|.json)?$/i
|
||||
)![1]
|
||||
|
||||
// Check that file name is an Integer
|
||||
if (isNaN(parseInt(fileName, 10))) {
|
||||
throw Error('Filenames must be numbers. Invalid fileName: ' + fileName)
|
||||
}
|
||||
return parseInt(fileName, 10)
|
||||
}
|
||||
|
||||
// We need to ensure that the files are numerically sorted (as opposed to lexicographically)
|
||||
const sortedImages = [...images.map(parseFileName)].sort(function (a, b) {
|
||||
return a - b
|
||||
})
|
||||
const sortedMetadata = [...metadata.map(parseFileName)].sort(function (a, b) {
|
||||
return a - b
|
||||
})
|
||||
let lastValue
|
||||
// Check each image is sequentially named with a number and has a matching metadata file
|
||||
for (let i = 0; i < sortedImages.length; i++) {
|
||||
const image = sortedImages[i]
|
||||
const json = sortedMetadata[i]
|
||||
if (image !== json) {
|
||||
throw Error('Images must have matching JSON files')
|
||||
}
|
||||
if (lastValue && lastValue + 1 !== image) {
|
||||
throw Error('Images must be sequential')
|
||||
}
|
||||
lastValue = image
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// @ts-nocheck
|
||||
// https://stackoverflow.com/questions/15478954/sort-array-elements-string-with-numbers-natural-sort/15479354#15479354
|
||||
export function naturalCompare(a: string, b: string) {
|
||||
var ax = []
|
||||
var bx = []
|
||||
a.replace(/(\d+)|(\D+)/g, function (_, $1, $2) {
|
||||
ax.push([$1 || Infinity, $2 || ''])
|
||||
})
|
||||
b.replace(/(\d+)|(\D+)/g, function (_, $1, $2) {
|
||||
bx.push([$1 || Infinity, $2 || ''])
|
||||
})
|
||||
|
||||
while (ax.length && bx.length) {
|
||||
var an = ax.shift()
|
||||
var bn = bx.shift()
|
||||
var nn = an[0] - bn[0] || an[1].localeCompare(bn[1])
|
||||
if (nn) return nn
|
||||
}
|
||||
|
||||
return ax.length - bx.length
|
||||
}
|
||||
Reference in New Issue
Block a user