Skip to content

Commit

Permalink
enabled ERC-4337 gasless minting 🐁
Browse files Browse the repository at this point in the history
  • Loading branch information
dysbulic committed Jun 11, 2024
1 parent 4abcca5 commit 12b02ed
Show file tree
Hide file tree
Showing 305 changed files with 973 additions and 455 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ You should now be able to click the trophy in the UI to create a new token type.
In order to publish the UI, you will need write access to the [’Chievemints GitHub Repository](https://github.com/MetaFam/chievemints/). Given that, just run `yarn ui:publish`.

![Flashy Octo](packages/ui/public/favicon.svg)

## Uploading Metadata

The gating tokens need to have metadata files uploaded to IPFS in order for them to display correctly. This is done by running the `yarn gating-metadata` task in the `packages/contracts/` subdirectory.
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"name": "@chievemints",
"name": "@chievemints",
"author": {
"name": "dysbulic",
"email": "dys@dhappy.org"
"name": "dys",
"email": "d@dhappy.org"
},
"version": "0.3.0",
"version": "0.4.19",
"license": "CC0-1.0",
"private": true,
"scripts": {
"ui:start": "yarn workspace @chievemints/ui dev",
"ui:test": "yarn workspace @chievemints/ui test",
"ui:publish": "yarn ui:build && yarn gh:publish",
"ui:publish:op": "yarn ui:build && yarn gh:publish:op",
"ui:build": "yarn workspace @chievemints/ui build",
"ui:preview": "yarn workspace @chievemints/ui preview",
"hh:node": "yarn workspace @chievemints/contracts chain",
Expand All @@ -32,11 +32,12 @@
"ui:theme": "yarn workspace @chievemints/ui theme",
"ui:watch": "yarn workspace @chievemints/ui watch",
"cm:grant": "yarn workspace @chievemints/contracts hardhat grant",
"cm:disable": "yarn workspace @chievemints/contracts hardhat disable",
"cm:metadata": "yarn workspace @chievemints/contracts gating-metadata"
},
"workspaces": {
"packages": [
"packages/*"
"pkgs/*"
]
},
"packageManager": "[email protected]",
Expand Down
74 changes: 0 additions & 74 deletions packages/ui/src/App.tsx

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,15 @@ if(!apiKey[defaultNetwork]) {
)
}

type EtherscannedHardhatConfig = HardhatUserConfig & {
etherscan: { apiKey: Record<string, string> }
typechain: { target: string, outDir: string }
}

const gasMultiplier = 1.5
const infuraId = process.env.INFURA_ID ?? ''
const alchemyId = process.env.ALCHEMY_ID ?? ''
const config: HardhatUserConfig = {
const config: EtherscannedHardhatConfig = {
defaultNetwork,

paths: {
Expand Down Expand Up @@ -300,7 +305,7 @@ task('grant', 'Grant a role')

const roleId = await rolesLibrary.roleIndexForName(role)
if(roleId === 0) throw new Error(`Can’t find “${role}” (must be capitalized).`)
let tx
let tx
if(token) {
tx = await contract['grantRole(uint8,address,uint256,bool)'](roleId, user, token, !!args.singleUse)
} else {
Expand All @@ -314,6 +319,33 @@ task('grant', 'Grant a role')
console.info(` 🕋 Tx: ${tx.hash}`)
})

task('disable', 'Disable a role')
.addParam('role', 'Role to grant')
.addParam('index', 'Index of the token to modify')
.setAction(async (args, { ethers }) => {
const { contract, name: contractName } = (
load({ filenameBase: 'Bulk*', ethers, config })
)
let { role, index } = args
console.log(
` 🍍 Disabling ${chalk.hex('#E1A47B')(role)} role`
+ ` on ${chalk.hex('#E16464')(contractName)}`
+ ` for token index #${chalk.hex('#E11F83')(index)}`
)
const { contract: rolesLibrary } = (
load({ filenameBase: 'Roles*', ethers, config })
)
const roleId = await rolesLibrary.roleIndexForName(role)
if(roleId === 0) throw new Error(`Can’t find “${role}” (must be capitalized).`)
let tx = await contract.disableRole(roleId, index)
const gas = {
limit: tx.gasLimit.toBigInt() as bigint,
price: tx.gasPrice.toBigInt() as bigint,
}
console.log(` ⛽ ${Number((gas.limit * gas.price) / 10n**10n) / 10**8}`)
console.info(` 🕋 Tx: ${tx.hash}`)
})

task('wallet', 'Create a wallet (pk) link', async (_, { ethers }) => {
const randomWallet = ethers.Wallet.createRandom()
const privateKey = randomWallet._signingKey().privateKey
Expand Down
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const main = async () => {
)

const templates = path.join(metadataDir, 'templates', '*.json5')
const files = await Promise.all(
const files = await Promise.all(
glob.sync(templates).map(async (file) => {
const type = file.replace(/^.*\//, '').replace(/\.json5$/, '')
console.debug(
Expand All @@ -91,7 +91,7 @@ const main = async () => {
}
})
return new File(
JSON.stringify(template, null, 2),
[JSON.stringify(template, null, 2)],
`${type}.json`,
{ type: 'application/json' },
)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions packages/ui/.env → pkgs/ui/.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# VITE_IPFS_LINK_PATTERN=http://{v1cid}.ipfs.localhost:8080/{path}
VITE_CHAIN_NAME=polygon
VITE_CHAIN_NAME=optimisticEthereum
VITE_process.env.NODE_DEBUG=''
VITE_RAW_global.WebSocket=window.WebSocket
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 7 additions & 4 deletions packages/ui/package.json → pkgs/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
"webpack:watch": "webpack --watch",
"webpack:serve": "webpack serve",
"webpack:analyze": "yarn webpack --profile --json > bundle-stats.json && yarn webpack-bundle-analyzer --port 9898 bundle-stats.json dist/",
"gh:publish": "gh-pages --dist dist/ --dotfiles --message 'Updatin’ GitHub Pages'"
"gh:publish": "gh-pages --dist dist/ --dotfiles --message 'Updatin’ GitHub Pages'",
"gh:publish:op": "gh-pages --dist dist/ --dotfiles --remote op-gh --message 'Updatin’ Optimistic GitHub Pages'"
},
"dependencies": {
"@biconomy/account": "^4.4.6",
"@react-three/fiber": "^8.13.0",
"@tanstack/react-query": "^5.40.1",
"@tippyjs/react": "^4.2.6",
"@types/three": "^0.152.1",
"@walletconnect/web3-provider": "^1.8.0",
"connectkit": "^1.6.0",
"connectkit": "^1.8.0",
"dotenv": "^16.0.0",
"graphql": "^16.5.0",
"ipfs-http-client": "^57.0.3",
Expand All @@ -41,8 +44,8 @@
"remark-gfm": "^3.0.1",
"three": "^0.153.0",
"util": "^0.12.5",
"viem": "^1.21.4",
"wagmi": "^1.4.13"
"viem": "^2.13.8",
"wagmi": "^2.9.11"
},
"devDependencies": {
"@babel/core": "^7.18.10",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes
83 changes: 83 additions & 0 deletions pkgs/ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@

import { Helmet } from 'react-helmet'
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
} from '@apollo/client'
import {
HashRouter as Router,
Routes,
Route,
} from 'react-router-dom'
import React from 'react'
import { WagmiProvider } from 'wagmi'
import { ConnectKitProvider } from 'connectkit'
import { ToastContainer } from 'react-toastify'
import { nftGraph } from '@/config'
import { Web3ContextProvider } from '@/lib/hooks'
import { config as wagmiConfig } from './lib/ConnectKit'
import { Spinner } from './components/Spinner'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

const Home = React.lazy(() => import('./pages/home'))
const New = React.lazy(() => import('./pages/new'))
const View = React.lazy(() => import('./pages/view'))
const Edit = React.lazy(() => import('./pages/edit'))
const Disburse = React.lazy(() => import('./pages/disburse'))
const SelfMint = React.lazy(() => import('./pages/self-mint'))
const Owners = React.lazy(() => import('./pages/owners'))
const Permissions = React.lazy(() => import('./pages/permissions'))
const FreeMushroom = React.lazy(() => import('./pages/mushroom'))

const apolloClient = new ApolloClient({
uri: nftGraph,
cache: new InMemoryCache(),
})

const queryClient = new QueryClient();

const App: React.FC = () => (
<>
<Helmet>
<link rel="shortcut icon" href="favicon.svg"/>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
</Helmet>
<ApolloProvider client={apolloClient}>
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<ConnectKitProvider>
<Web3ContextProvider>
<React.Suspense fallback={<Spinner/>}>
<Router>
<Routes>
<Route path="/new" element={<New/>} />
<Route path="/view/:nftId" element={<View/>} />
<Route path="/self-mint/:nftId" element={<SelfMint/>} />
<Route path="/disburse/:nftId" element={<Disburse/>} />
<Route path="/owners/:nftId" element={<Owners/>} />
<Route path="/edit/:nftId" element={<Edit/>} />
<Route path="/permissions/:nftId" element={<Permissions/>} />
<Route path="/mushy" element={<FreeMushroom/>} />
<Route path="/" element={<Home/>} />
</Routes>
</Router>
</React.Suspense>
</Web3ContextProvider>
</ConnectKitProvider>
</QueryClientProvider>
</WagmiProvider>
</ApolloProvider>
<ToastContainer
position="bottom-center"
autoClose={15000}
closeOnClick
pauseOnHover
/>
</>
)

export default App
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,11 @@ const MediaDisplay: React.FC<{
setType(type)
}, [content])

const set = ({ target: { files } }: (
{ target: { files: Maybe<FileList> } }
const set = ({ target: { value } }: (
{ target: { value: string } }
)) => {
if(files.length >= 1 && files[0]) {
setValue(prop, files[0])
setFilename(files[0].name)
}
setValue(prop, value)
setFilename(value)
}

const remove = (evt: React.MouseEvent) => {
Expand All @@ -243,20 +241,10 @@ const MediaDisplay: React.FC<{
<div className={fs.selector}>
<h3>{capitalize(prop)}</h3>
<input
type="file"
onChange={set}
ref={input}
{...{ accept }}
/>
{filename && <h4>{filename}</h4>}
{!content &&(
<button
type="button"
onClick={() => input.current?.click()}
>
Set
</button>
)}
</div>
{content && (
<div className={fs.content}>
Expand All @@ -280,10 +268,7 @@ const MediaDisplay: React.FC<{
}
case 'model': {
return (
<ThreeDScene
className={fs.model}
model={url}
/>
<ThreeDScene className={fs.model} model={url}/>
)
}
default: {
Expand Down
Loading

0 comments on commit 12b02ed

Please sign in to comment.