Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: safe integration #181

Open
wants to merge 1 commit into
base: integrations
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions app/(general)/integration/safe/create/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// import { WalletConnect } from '@/components/blockchain/wallet-connect'
import { FormDeploySafe } from '@/integrations/safe/components/form-deploy-safe'

export default function PageIntegration() {
// use safe hook
return (
<section className="w-full lg:mt-10">
<div className="container mx-auto mt-10 max-w-screen-xl gap-6 text-start">
{/* <WalletConnect className="inline-block" /> */}
<FormDeploySafe />
</div>
</section>
)
}
76 changes: 76 additions & 0 deletions app/(general)/integration/safe/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use client'
import { ReactNode } from 'react'

import { motion } from 'framer-motion'
import Image from 'next/image'
import { usePathname } from 'next/navigation'
import Balancer from 'react-wrap-balancer'

import { IsDarkTheme } from '@/components/shared/is-dark-theme'
import { IsLightTheme } from '@/components/shared/is-light-theme'
import { LinkComponent } from '@/components/shared/link-component'
import { FADE_DOWN_ANIMATION_VARIANTS } from '@/config/design'
import { turboIntegrations } from '@/data/turbo-integrations'
import { SafeAppProvider } from '@/integrations/safe/safe-provider'
import { cn } from '@/lib/utils'

const integrationData = turboIntegrations.safe

const createPath = '/integration/safe/create'
const managePath = '/integration/safe/manage'

export default function LayoutIntegration({ children }: { children: ReactNode }) {
const pathname = usePathname()

return (
<SafeAppProvider>
<div className="flex-center flex-col items-center justify-center text-center">
<motion.div
animate="show"
className="max-w-3xl px-5 text-center xl:px-0"
initial="hidden"
viewport={{ once: true }}
whileInView="show"
variants={{
hidden: {},
show: {
transition: {
staggerChildren: 0.15,
},
},
}}>
<IsLightTheme>
<Image alt="Starter logo" className="mx-auto" height={100} src={integrationData.imgDark} width={100} />
</IsLightTheme>
<IsDarkTheme>
<Image alt="Starter logo" className="mx-auto" height={100} src={integrationData.imgLight} width={100} />
</IsDarkTheme>
<motion.h1
className="text-gradient-sand my-8 text-center text-4xl font-bold tracking-[-0.02em] drop-shadow-sm md:text-8xl md:leading-[6rem]"
variants={FADE_DOWN_ANIMATION_VARIANTS}>
{integrationData.name}
</motion.h1>
<motion.p className="my-4 text-xl" variants={FADE_DOWN_ANIMATION_VARIANTS}>
<Balancer>{integrationData.description}</Balancer>
</motion.p>
<motion.div className="my-4 text-xl" variants={FADE_DOWN_ANIMATION_VARIANTS}>
<LinkComponent className="btn btn-primary" href={integrationData.url}>
Documentation
</LinkComponent>
</motion.div>
<motion.div className="mt-8 flex flex-col justify-center gap-x-14 text-2xl sm:flex-row" variants={FADE_DOWN_ANIMATION_VARIANTS}>
<LinkComponent href={createPath}>
<button className={cn('btn hover:opacity-75', pathname === managePath && 'opacity-50')}>Create new Safe</button>
</LinkComponent>
<LinkComponent href={managePath}>
<button className={cn('btn hover:opacity-75', pathname === createPath && 'opacity-50')}>Manage Safe</button>
</LinkComponent>
</motion.div>
<motion.div className="flex h-full w-full justify-center" variants={FADE_DOWN_ANIMATION_VARIANTS}>
<div>{children}</div>
</motion.div>
</motion.div>
</div>
</SafeAppProvider>
)
}
21 changes: 21 additions & 0 deletions app/(general)/integration/safe/manage/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// import { WalletConnect } from '@/components/blockchain/wallet-connect'
import { FormSendSafeTransaction } from '@/integrations/safe/components/form-send-safe-transaction'
import { ManageSafe } from '@/integrations/safe/components/manage-safe'
import { PendingSafeTransactions } from '@/integrations/safe/components/pending-safe-transactions'
import { ConnectSafe } from '@/integrations/safe/hooks/use-connect-safe'

export default function PageIntegration() {
return (
<section className="w-full lg:mt-10">
<div className="container mx-auto mt-10 max-w-screen-xl gap-6 text-start">
{/* <WalletConnect className="inline-block" /> */}
<ConnectSafe>
<ManageSafe />
<FormSendSafeTransaction />
<PendingSafeTransactions />
{/* <TxnsHistory /> */}
</ConnectSafe>
</div>
</section>
)
}
9 changes: 9 additions & 0 deletions app/(general)/integration/safe/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IntegrationOgImage } from "@/components/ui/social/og-image-integrations"

export const runtime = "edge"
export const size = {
width: 1200,
height: 630,
}

export default IntegrationOgImage("safe")
5 changes: 5 additions & 0 deletions app/(general)/integration/safe/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from 'next/navigation'

export default function PageIntegration() {
redirect('/integration/safe/create')
}
9 changes: 9 additions & 0 deletions app/(general)/integration/safe/twitter-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Image from "./opengraph-image"

export const runtime = "edge"
export const size = {
width: 1200,
height: 630,
}

export default Image
9 changes: 9 additions & 0 deletions data/turbo-integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ export const turboIntegrations = {
imgDark: "/integrations/connext.png",
category: "protocols",
},
safe: {
name: 'Safe',
href: '/integration/safe',
url: 'https://docs.safe.global/',
description: 'Safe is the most trusted decentralized custody protocol and collective asset management platform on Ethereum and the EVM',
imgLight: '/integrations/safe-light.svg',
imgDark: '/integrations/safe-dark.svg',
category: "protocols",
},
gelato: {
name: "Gelato",
href: "/integration/gelato",
Expand Down
86 changes: 86 additions & 0 deletions integrations/safe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Safe TurboETH Integration

This TurboETH integration provides a suite of hooks and components to facilitate interaction with ERC1155 contracts. In consideration of the numerous extensions and features offered by ERC1155, this integration is based on a contract from [solidstate](https://github.com/solidstate-network/solidstate-solidity), incorporating the following features and access controls:

**Features:**

- Mintable
- Enumerable
- ERC1155BaseStorage
- Single Approve

**Access Control:**

- Ownable

## ABI and Bytecode

Within the `artifacts` directory, you will find the `erc1155-abi.ts` file, containing the ABI from the contract that was used to generate the [Wagmi CLI](https://wagmi.sh/cli/getting-started) contract hooks. The `erc1155-bytecode.ts` file contains the bytecode used for contract deployment. If you wish to use a different ERC1155 contract with distinct features/extensions, simply update the ABI and bytecode, and then regenerate the Wagmi CLI hooks using the command `pnpm wagmi generate`.

## Hooks:

- `useErc1155TokenStorage`: Utilizes Jotai and local storage to persist the deployed token's address within the browser's local storage. It updates the value across all components observing it whenever a new deployment occurs.
- `useERC1155Metadata`: Accepts contract and token information (contract address, chainId, tokenId, and ipfsGatewayUrl) and returns a query object from `tanstack-query` with the token metadata information. The hook and the components adhere to the "ERC1155 Metadata JSON Schema" convention for metadata formatting. Learn more [here](https://eips.ethereum.org/EIPS/eip-1155).

## Components:

This integration includes read and write/deploy components. The read components solely access the contract information and retrieve the response, whereas the write/deploy components are capable of deploying the contract and performing write actions, requiring a signer and a transaction to be submitted.

**Read Components:**

- `ERC1155Name`: Returns the contract's name.
- `ERC1155Symbol`: Returns the contract's symbol.
- `ERC1155TotalSupply`: Returns the total supply of the contract.
- `ERC1155OwnerOf`: Returns the owners of a specific token.
- `ERC1155TokenUriName`: Returns the name of a specific token.
- `ERC1155TokenUriDescription`: Returns the description of a specific token.
- `ERC1155TokenUriImage`: Returns the image of a specific token.
- `Erc1155Read`: Returns a card with aggregate information about the contract and a selected token ID.

**Write/Deploy Components:**

- `ERC1155Deploy`: Form for contract deployment. Upon deployment, the contract address is saved in local storage under the key `erc1155-token`.
- `ERC1155DeployTest`: Form for test contract deployment. Upon deployment, the contract address is saved in local storage under the key `erc1155-token`.
- `Erc1155WriteMint`: Form for minting new NFTs. Only the contract owner can mint new NFTs.
- `Erc1155WriteApprove`: Form for approving an address's permission to transfer a token on behalf of the token holder. Only the token holder can perform the approved transaction.
- `Erc1155WriteTransfer`: Form for transferring a token to a different address. Only a token owner or approved address can transfer.

File Structure

```
integrations/erc1155
├─ artifacts/
| ├─ core/
│ | ├─ erc1155-abi.ts
│ | ├─ erc1155-bytecode.ts
| ├─ test/
│ | ├─ erc1155-abi.ts
│ | ├─ erc1155-bytecode.ts
├─ components/
│ ├─ erc1155-deploy.tsx
│ ├─ erc1155-name.tsx
│ ├─ erc1155-owner-of.tsx
│ ├─ erc1155-read.tsx
│ ├─ erc1155-set-token-storage.tsx
│ ├─ erc1155-symbol.tsx
│ ├─ erc1155-token-uri-description.tsx
│ ├─ erc1155-token-uri-image.tsx
│ ├─ erc1155-token-uri-name.tsx
│ ├─ erc1155-token-uri.tsx
│ ├─ erc1155-contract-uri.tsx
│ ├─ erc1155-total-supply.tsx
│ ├─ erc1155-write-approve.tsx
│ ├─ erc1155-write-mint.tsx
│ ├─ erc1155-write-transfer.tsx
│ ├─ erc1155-write-batch-transfer.tsx
├─ generated/
│ ├─ erc1155-wagmi.ts
├─ hooks/
│ ├─ use-erc1155-metadata.ts
│ ├─ use-erc1155-token-storage.ts
├─ utils/
│ ├─ types.ts
├─ index.ts
├─ wagmi.config.ts
├─ README.md
```
Loading
Loading