Added contract helpers for minter, sg721 & whitelist

This commit is contained in:
Serkan Reis
2022-07-14 13:16:50 +03:00
parent 4dde6db215
commit a0affdaa4d
38 changed files with 2615 additions and 1465 deletions
-170
View File
@@ -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)
}
-90
View File
@@ -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')
}
}
}
+45
View File
@@ -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
}
}
+21
View File
@@ -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
}