mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-22 01:46:51 +01:00
web3 updates
This commit is contained in:
parent
592498fb9a
commit
feee0c678b
10463
package-lock.json
generated
10463
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,8 @@
|
|||||||
"@nanostores/query": "^0.2.10",
|
"@nanostores/query": "^0.2.10",
|
||||||
"@nanostores/react": "^0.7.2",
|
"@nanostores/react": "^0.7.2",
|
||||||
"@radix-ui/react-select": "^2.0.0",
|
"@radix-ui/react-select": "^2.0.0",
|
||||||
"@rainbow-me/rainbowkit": "^1.3.0",
|
"@rainbow-me/rainbowkit": "^2.0.2",
|
||||||
|
"@tanstack/react-query": "^5.27.5",
|
||||||
"astro": "4.5.2",
|
"astro": "4.5.2",
|
||||||
"astro-expressive-code": "^0.33.4",
|
"astro-expressive-code": "^0.33.4",
|
||||||
"astro-redirect-from": "^1.0.6",
|
"astro-redirect-from": "^1.0.6",
|
||||||
@ -76,8 +77,8 @@
|
|||||||
"sharp": "^0.33.2",
|
"sharp": "^0.33.2",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"viem": "^1.19.13",
|
"viem": "^2.8.5",
|
||||||
"wagmi": "^1.4.12"
|
"wagmi": "^2.5.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.42.1",
|
"@playwright/test": "^1.42.1",
|
||||||
|
@ -1,42 +1,22 @@
|
|||||||
import { formatEther, formatUnits } from 'viem'
|
import { useAccount, useEnsName } from 'wagmi'
|
||||||
import { useAccount, useEnsName, useNetwork } from 'wagmi'
|
|
||||||
import type {
|
|
||||||
SendTransactionArgs,
|
|
||||||
WriteContractPreparedArgs
|
|
||||||
} from 'wagmi/actions'
|
|
||||||
import styles from './Data.module.css'
|
import styles from './Data.module.css'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $selectedToken } from '@features/Web3/stores'
|
import { $amount, $selectedToken } from '@features/Web3/stores'
|
||||||
import { truncateAddress } from '@features/Web3/lib/truncateAddress'
|
import { truncateAddress } from '@features/Web3/lib/truncateAddress'
|
||||||
|
|
||||||
export function Data({
|
export function Data({
|
||||||
to,
|
to,
|
||||||
ensResolved,
|
ensResolved,
|
||||||
txConfig,
|
|
||||||
isDisabled
|
isDisabled
|
||||||
}: {
|
}: {
|
||||||
to: `0x${string}` | null | undefined
|
to: `0x${string}` | null | undefined
|
||||||
ensResolved: string | null | undefined
|
ensResolved: string | null | undefined
|
||||||
txConfig: SendTransactionArgs | WriteContractPreparedArgs | undefined
|
|
||||||
isDisabled: boolean
|
isDisabled: boolean
|
||||||
}) {
|
}) {
|
||||||
const { chain } = useNetwork()
|
const { address: from, chain } = useAccount()
|
||||||
const { address: from } = useAccount()
|
|
||||||
const { data: ensFrom } = useEnsName({ address: from, chainId: 1 })
|
const { data: ensFrom } = useEnsName({ address: from, chainId: 1 })
|
||||||
const selectedToken = useStore($selectedToken)
|
const selectedToken = useStore($selectedToken)
|
||||||
|
const amount = useStore($amount)
|
||||||
// Derive display values in preview from actual tx config
|
|
||||||
// instead from our form stores
|
|
||||||
const value =
|
|
||||||
(txConfig as SendTransactionArgs)?.value ||
|
|
||||||
(txConfig as WriteContractPreparedArgs)?.request?.args?.[1] ||
|
|
||||||
'0'
|
|
||||||
const displayAmountFromConfig =
|
|
||||||
selectedToken?.decimals === 18
|
|
||||||
? formatEther(value as bigint)
|
|
||||||
: selectedToken?.decimals
|
|
||||||
? formatUnits(value as bigint, selectedToken.decimals)
|
|
||||||
: '0'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className={styles.table} aria-disabled={isDisabled}>
|
<table className={styles.table} aria-disabled={isDisabled}>
|
||||||
@ -66,7 +46,7 @@ export function Data({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className={styles.amount}>
|
<span className={styles.amount}>
|
||||||
{displayAmountFromConfig} {selectedToken?.symbol}
|
{amount} {selectedToken?.symbol}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Loader } from '@components/Loader'
|
import { Loader } from '@components/Loader'
|
||||||
import { usePrepareSend } from '@features/Web3/hooks/usePrepareSend'
|
|
||||||
import { useSend } from '@features/Web3/hooks/useSend'
|
import { useSend } from '@features/Web3/hooks/useSend'
|
||||||
import { $isInitSend } from '@features/Web3/stores'
|
import { $isInitSend } from '@features/Web3/stores'
|
||||||
import { useEnsAddress, useEnsName } from 'wagmi'
|
import { useEnsAddress, useEnsName } from 'wagmi'
|
||||||
@ -17,12 +16,7 @@ export function Preview() {
|
|||||||
chainId: 1
|
chainId: 1
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const { handleSend, isLoading, error } = useSend()
|
||||||
data: txConfig,
|
|
||||||
error: prepareError,
|
|
||||||
isError: isPrepareError
|
|
||||||
} = usePrepareSend({ to })
|
|
||||||
const { handleSend, isLoading, error } = useSend({ txConfig })
|
|
||||||
|
|
||||||
// TODO: Cancel flow if chain changes in preview as this can mess with token selection
|
// TODO: Cancel flow if chain changes in preview as this can mess with token selection
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
@ -32,16 +26,9 @@ export function Preview() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Data
|
<Data to={to} ensResolved={ensResolved} isDisabled={isLoading} />
|
||||||
to={to}
|
|
||||||
ensResolved={ensResolved}
|
|
||||||
txConfig={txConfig}
|
|
||||||
isDisabled={isLoading}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{error || prepareError ? (
|
{error ? <div className={styles.alert}>{error}</div> : null}
|
||||||
<div className={styles.alert}>{error || prepareError}</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<footer className={styles.actions}>
|
<footer className={styles.actions}>
|
||||||
<button
|
<button
|
||||||
@ -50,7 +37,7 @@ export function Preview() {
|
|||||||
await handleSend()
|
await handleSend()
|
||||||
}}
|
}}
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
disabled={isLoading || !txConfig || isPrepareError}
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
{isLoading ? <Loader /> : 'Make it rain'}
|
{isLoading ? <Loader /> : 'Make it rain'}
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { $txHash, $isInitSend } from '@features/Web3/stores'
|
import { $txHash, $isInitSend } from '@features/Web3/stores'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import styles from './Success.module.css'
|
import styles from './Success.module.css'
|
||||||
import { useNetwork } from 'wagmi'
|
import { useAccount } from 'wagmi'
|
||||||
import { ExplorerLink } from './ExplorerLink'
|
import { ExplorerLink } from './ExplorerLink'
|
||||||
|
|
||||||
const title = `You're amazing, thanks!`
|
const title = `You're amazing, thanks!`
|
||||||
const description = `Your transaction is on its way. You can check the status on`
|
const description = `Your transaction is on its way. You can check the status on`
|
||||||
|
|
||||||
export function Success() {
|
export function Success() {
|
||||||
const { chain } = useNetwork()
|
const account = useAccount()
|
||||||
const txHash = useStore($txHash)
|
const txHash = useStore($txHash)
|
||||||
|
|
||||||
const explorerName = chain?.blockExplorers?.default.name
|
const explorerName = account?.chain?.blockExplorers?.default.name
|
||||||
const explorerUrl = chain?.blockExplorers?.default.url
|
const explorerUrl = account?.chain?.blockExplorers?.default.url
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.success}>
|
<div className={styles.success}>
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
|
import '../lib/polyfills'
|
||||||
import { RainbowKitProvider } from '@rainbow-me/rainbowkit'
|
import { RainbowKitProvider } from '@rainbow-me/rainbowkit'
|
||||||
import { WagmiConfig } from 'wagmi'
|
import { WagmiProvider } from 'wagmi'
|
||||||
import { wagmiConfig, chains, theme } from '../lib/rainbowkit'
|
import { wagmiConfig, theme } from '../lib/rainbowkit'
|
||||||
import { Web3Form } from './Form'
|
import { Web3Form } from './Form'
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
|
|
||||||
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
export function Web3() {
|
export function Web3() {
|
||||||
return (
|
return (
|
||||||
<WagmiConfig config={wagmiConfig}>
|
<WagmiProvider config={wagmiConfig}>
|
||||||
<RainbowKitProvider chains={chains} theme={theme}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<Web3Form />
|
<RainbowKitProvider theme={theme}>
|
||||||
</RainbowKitProvider>
|
<Web3Form />
|
||||||
</WagmiConfig>
|
</RainbowKitProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</WagmiProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { useFetchTokens } from './useFetchTokens'
|
|||||||
|
|
||||||
test('useFetchTokens does not fetch anything when no chain or address are present', async () => {
|
test('useFetchTokens does not fetch anything when no chain or address are present', async () => {
|
||||||
vi.mock('wagmi', () => ({
|
vi.mock('wagmi', () => ({
|
||||||
useNetwork: () => ({ chain: undefined }),
|
useChainId: () => undefined,
|
||||||
useAccount: () => ({ address: undefined })
|
useAccount: () => ({ address: undefined })
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import useSWR, { type SWRResponse } from 'swr'
|
import useSWR, { type SWRResponse } from 'swr'
|
||||||
import { useNetwork, useAccount } from 'wagmi'
|
import { useChainId, useAccount } from 'wagmi'
|
||||||
import type { GetToken } from './types'
|
import type { GetToken } from './types'
|
||||||
|
|
||||||
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
||||||
@ -10,7 +10,7 @@ const apiUrl = import.meta.env.PUBLIC_WEB3_API_URL
|
|||||||
// Wrapper for fetching user tokens with swr.
|
// Wrapper for fetching user tokens with swr.
|
||||||
//
|
//
|
||||||
export function useFetchTokens(): SWRResponse<GetToken[] | undefined, Error> {
|
export function useFetchTokens(): SWRResponse<GetToken[] | undefined, Error> {
|
||||||
const { chain } = useNetwork()
|
const chainId = useChainId()
|
||||||
const { address } = useAccount()
|
const { address } = useAccount()
|
||||||
|
|
||||||
const [url, setUrl] = useState<string | undefined>()
|
const [url, setUrl] = useState<string | undefined>()
|
||||||
@ -20,14 +20,14 @@ export function useFetchTokens(): SWRResponse<GetToken[] | undefined, Error> {
|
|||||||
// Set url only after we have all data loaded on client,
|
// Set url only after we have all data loaded on client,
|
||||||
// preventing initial fetch.
|
// preventing initial fetch.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!address || !chain?.id) {
|
if (!address || !chainId) {
|
||||||
setUrl(undefined)
|
setUrl(undefined)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${apiUrl}/balance?address=${address}&chainId=${chain?.id}`
|
const url = `${apiUrl}/balance?address=${address}&chainId=${chainId}`
|
||||||
setUrl(url)
|
setUrl(url)
|
||||||
}, [address, chain?.id])
|
}, [address, chainId])
|
||||||
|
|
||||||
return fetchResults
|
return fetchResults
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export * from './usePrepareSend'
|
|
@ -1,43 +0,0 @@
|
|||||||
import { test, expect, vi } from 'vitest'
|
|
||||||
import { prepare } from './prepare'
|
|
||||||
import * as wagmiActionsMock from '../../../../../test/__mocks__/wagmi/actions'
|
|
||||||
|
|
||||||
test('prepare with undefined params', async () => {
|
|
||||||
try {
|
|
||||||
await prepare(undefined, undefined, undefined, undefined)
|
|
||||||
expect(true).toBe(false)
|
|
||||||
} catch (e) {
|
|
||||||
expect(true).toBe(true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
test('prepare with isNative true uses correct method', async () => {
|
|
||||||
const selectedToken = {
|
|
||||||
address: '0x0',
|
|
||||||
decimals: 18
|
|
||||||
// Add other required properties here
|
|
||||||
}
|
|
||||||
|
|
||||||
const amount = '1'
|
|
||||||
const to = '0xabcdef1234567890'
|
|
||||||
const chainId = 1
|
|
||||||
|
|
||||||
const spy = vi.spyOn(wagmiActionsMock, 'prepareSendTransaction')
|
|
||||||
await prepare(selectedToken as any, amount, to, chainId)
|
|
||||||
expect(spy).toHaveBeenCalledOnce()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('prepare with isNative false uses correct method', async () => {
|
|
||||||
const selectedToken = {
|
|
||||||
address: '0xabcdef1234567890',
|
|
||||||
decimals: 18
|
|
||||||
}
|
|
||||||
|
|
||||||
const amount = '1'
|
|
||||||
const to = '0xabcdef1234567890'
|
|
||||||
const chainId = 1
|
|
||||||
|
|
||||||
const spy = vi.spyOn(wagmiActionsMock, 'prepareWriteContract')
|
|
||||||
await prepare(selectedToken as any, amount, to, chainId)
|
|
||||||
expect(spy).toHaveBeenCalledOnce()
|
|
||||||
})
|
|
@ -1,42 +0,0 @@
|
|||||||
import { parseEther, parseUnits } from 'viem'
|
|
||||||
import {
|
|
||||||
prepareSendTransaction,
|
|
||||||
prepareWriteContract,
|
|
||||||
type SendTransactionArgs,
|
|
||||||
type WriteContractPreparedArgs
|
|
||||||
} from 'wagmi/actions'
|
|
||||||
import { abiErc20Transfer } from './abiErc20Transfer'
|
|
||||||
import type { GetToken } from '../useFetchTokens'
|
|
||||||
|
|
||||||
export async function prepare(
|
|
||||||
selectedToken: GetToken | undefined,
|
|
||||||
amount: string | undefined,
|
|
||||||
to: `0x${string}` | null | undefined,
|
|
||||||
chainId: number | undefined
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!chainId ||
|
|
||||||
!to ||
|
|
||||||
!amount ||
|
|
||||||
!selectedToken ||
|
|
||||||
!selectedToken?.address ||
|
|
||||||
!selectedToken?.decimals
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
const isNative = selectedToken.address === '0x0'
|
|
||||||
const requestNative = { chainId, to, value: parseEther(amount) }
|
|
||||||
const requestErc20 = {
|
|
||||||
chainId,
|
|
||||||
address: selectedToken.address,
|
|
||||||
abi: abiErc20Transfer,
|
|
||||||
functionName: 'transfer',
|
|
||||||
args: [to, parseUnits(amount, selectedToken.decimals)]
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = isNative
|
|
||||||
? ((await prepareSendTransaction(requestNative)) as SendTransactionArgs)
|
|
||||||
: ((await prepareWriteContract(requestErc20)) as WriteContractPreparedArgs)
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react'
|
|
||||||
import { useStore } from '@nanostores/react'
|
|
||||||
import { useNetwork } from 'wagmi'
|
|
||||||
import type {
|
|
||||||
SendTransactionArgs,
|
|
||||||
WriteContractPreparedArgs
|
|
||||||
} from 'wagmi/actions'
|
|
||||||
import { $amount, $selectedToken } from '@features/Web3/stores'
|
|
||||||
import { prepare } from './prepare'
|
|
||||||
|
|
||||||
export function usePrepareSend({
|
|
||||||
to
|
|
||||||
}: {
|
|
||||||
to: `0x${string}` | null | undefined
|
|
||||||
}) {
|
|
||||||
const selectedToken = useStore($selectedToken)
|
|
||||||
const amount = useStore($amount)
|
|
||||||
const { chain } = useNetwork()
|
|
||||||
|
|
||||||
const [txConfig, setTxConfig] = useState<
|
|
||||||
SendTransactionArgs | WriteContractPreparedArgs
|
|
||||||
>()
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
const [isError, setIsError] = useState(false)
|
|
||||||
const [error, setError] = useState<string | undefined>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function init() {
|
|
||||||
if (!selectedToken || !amount || !to || !chain?.id) return
|
|
||||||
|
|
||||||
setError(undefined)
|
|
||||||
setIsError(false)
|
|
||||||
setIsLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const config = await prepare(selectedToken, amount, to, chain.id)
|
|
||||||
setTxConfig(config)
|
|
||||||
} catch (error: unknown) {
|
|
||||||
console.error((error as Error).message)
|
|
||||||
|
|
||||||
setIsError(true)
|
|
||||||
|
|
||||||
// only expose useful errors in UI
|
|
||||||
if (
|
|
||||||
(error as Error).message.includes(
|
|
||||||
'this transaction exceeds the balance of the account.'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
setError(undefined)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
init()
|
|
||||||
}, [selectedToken || amount || to || chain?.id])
|
|
||||||
|
|
||||||
return { data: txConfig, isLoading, isError, error }
|
|
||||||
}
|
|
@ -3,7 +3,13 @@ import { send } from './send'
|
|||||||
import * as wagmiActionsMock from '../../../../../test/__mocks__/wagmi/actions'
|
import * as wagmiActionsMock from '../../../../../test/__mocks__/wagmi/actions'
|
||||||
|
|
||||||
test('with undefined params', async () => {
|
test('with undefined params', async () => {
|
||||||
const result = await send(undefined, undefined)
|
const result = await send(
|
||||||
|
undefined as any,
|
||||||
|
undefined as any,
|
||||||
|
undefined as any,
|
||||||
|
undefined as any,
|
||||||
|
undefined as any
|
||||||
|
)
|
||||||
expect(result).toBeUndefined()
|
expect(result).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -11,10 +17,10 @@ test('with isNative true uses correct method', async () => {
|
|||||||
const selectedToken = {
|
const selectedToken = {
|
||||||
address: '0x0',
|
address: '0x0',
|
||||||
decimals: 18
|
decimals: 18
|
||||||
}
|
} as any
|
||||||
|
|
||||||
const spy = vi.spyOn(wagmiActionsMock, 'sendTransaction')
|
const spy = vi.spyOn(wagmiActionsMock, 'sendTransaction')
|
||||||
await send(selectedToken as any, {} as any)
|
await send({} as any, selectedToken, '1', '0xabcdef1234567890', 1)
|
||||||
expect(spy).toHaveBeenCalledOnce()
|
expect(spy).toHaveBeenCalledOnce()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -22,9 +28,9 @@ test('with isNative false uses correct method', async () => {
|
|||||||
const selectedToken = {
|
const selectedToken = {
|
||||||
address: '0xabcdef1234567890',
|
address: '0xabcdef1234567890',
|
||||||
decimals: 18
|
decimals: 18
|
||||||
}
|
} as any
|
||||||
|
|
||||||
const spy = vi.spyOn(wagmiActionsMock, 'writeContract')
|
const spy = vi.spyOn(wagmiActionsMock, 'writeContract')
|
||||||
await send(selectedToken as any, {} as any)
|
await send({} as any, selectedToken, '1', '0xabcdef1234567890', 1)
|
||||||
expect(spy).toHaveBeenCalledOnce()
|
expect(spy).toHaveBeenCalledOnce()
|
||||||
})
|
})
|
||||||
|
@ -1,21 +1,31 @@
|
|||||||
import {
|
import { sendTransaction, writeContract } from 'wagmi/actions'
|
||||||
sendTransaction as sendNative,
|
|
||||||
writeContract,
|
|
||||||
type SendTransactionArgs,
|
|
||||||
type WriteContractPreparedArgs
|
|
||||||
} from 'wagmi/actions'
|
|
||||||
import type { GetToken } from '../useFetchTokens'
|
import type { GetToken } from '../useFetchTokens'
|
||||||
|
import { parseEther, parseUnits } from 'viem'
|
||||||
|
import { abiErc20Transfer } from './abiErc20Transfer'
|
||||||
|
import type { UseConfigReturnType } from 'wagmi'
|
||||||
|
|
||||||
export async function send(
|
export async function send(
|
||||||
|
config: UseConfigReturnType,
|
||||||
selectedToken: GetToken | undefined,
|
selectedToken: GetToken | undefined,
|
||||||
config: SendTransactionArgs | WriteContractPreparedArgs | undefined
|
amount: string | undefined,
|
||||||
|
to: `0x${string}` | undefined,
|
||||||
|
chainId: number | undefined
|
||||||
) {
|
) {
|
||||||
if (!config || !selectedToken) return
|
if (!selectedToken?.decimals || !amount || !to) return
|
||||||
|
|
||||||
const result =
|
const isNative = selectedToken.address === '0x0'
|
||||||
selectedToken?.address === '0x0'
|
const requestNative = { chainId, to, value: parseEther(amount) }
|
||||||
? await sendNative(config as SendTransactionArgs)
|
const requestErc20 = {
|
||||||
: await writeContract(config as WriteContractPreparedArgs)
|
chainId,
|
||||||
|
address: selectedToken.address,
|
||||||
|
abi: abiErc20Transfer,
|
||||||
|
functionName: 'transfer',
|
||||||
|
args: [to, parseUnits(amount, selectedToken.decimals)]
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = isNative
|
||||||
|
? await sendTransaction(config, requestNative)
|
||||||
|
: await writeContract(config, requestErc20)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
import { $txHash, $selectedToken } from '@features/Web3/stores'
|
import { $txHash, $selectedToken, $amount } from '@features/Web3/stores'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import type {
|
|
||||||
SendTransactionArgs,
|
|
||||||
WriteContractPreparedArgs
|
|
||||||
} from 'wagmi/actions'
|
|
||||||
import { send } from './send'
|
import { send } from './send'
|
||||||
import { isUnhelpfulErrorMessage } from './isUnhelpfulErrorMessage'
|
import { isUnhelpfulErrorMessage } from './isUnhelpfulErrorMessage'
|
||||||
|
import { useAccount, useConfig } from 'wagmi'
|
||||||
|
|
||||||
export function useSend({
|
export function useSend() {
|
||||||
txConfig
|
|
||||||
}: {
|
|
||||||
txConfig: SendTransactionArgs | WriteContractPreparedArgs | undefined
|
|
||||||
}) {
|
|
||||||
const selectedToken = useStore($selectedToken)
|
const selectedToken = useStore($selectedToken)
|
||||||
|
const amount = useStore($amount)
|
||||||
|
const config = useConfig()
|
||||||
|
const { address, chainId } = useAccount()
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [isError, setIsError] = useState(false)
|
const [isError, setIsError] = useState(false)
|
||||||
@ -24,8 +20,8 @@ export function useSend({
|
|||||||
setIsError(false)
|
setIsError(false)
|
||||||
setError(undefined)
|
setError(undefined)
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
const result = await send(selectedToken, txConfig)
|
const hash = await send(config, selectedToken, amount, address, chainId)
|
||||||
$txHash.set(result?.hash)
|
if (hash) $txHash.set(hash)
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const errorMessage = (error as Error).message
|
const errorMessage = (error as Error).message
|
||||||
console.error(errorMessage)
|
console.error(errorMessage)
|
||||||
|
7
src/features/Web3/lib/polyfills.ts
Normal file
7
src/features/Web3/lib/polyfills.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Buffer } from 'buffer'
|
||||||
|
|
||||||
|
window.global = window.global ?? window
|
||||||
|
window.Buffer = window.Buffer ?? Buffer
|
||||||
|
window.process = window.process ?? { env: {} } // Minimal process polyfill
|
||||||
|
|
||||||
|
export {}
|
@ -1,32 +1,17 @@
|
|||||||
import { type Theme, getDefaultWallets } from '@rainbow-me/rainbowkit'
|
import { type Theme, getDefaultConfig } from '@rainbow-me/rainbowkit'
|
||||||
import { configureChains, createConfig } from 'wagmi'
|
|
||||||
import { mainnet, polygon, base, optimism } from 'wagmi/chains'
|
import { mainnet, polygon, base, optimism } from 'wagmi/chains'
|
||||||
import { infuraProvider } from 'wagmi/providers/infura'
|
|
||||||
import { publicProvider } from 'wagmi/providers/public'
|
|
||||||
|
|
||||||
const PUBLIC_INFURA_ID = import.meta.env.PUBLIC_INFURA_ID
|
|
||||||
const PUBLIC_WALLETCONNECT_ID = import.meta.env.PUBLIC_WALLETCONNECT_ID
|
const PUBLIC_WALLETCONNECT_ID = import.meta.env.PUBLIC_WALLETCONNECT_ID
|
||||||
const isProduction = import.meta.env.PROD
|
const isProduction = import.meta.env.PROD
|
||||||
|
|
||||||
if (isProduction && (!PUBLIC_INFURA_ID || !PUBLIC_WALLETCONNECT_ID)) {
|
if (isProduction && !PUBLIC_WALLETCONNECT_ID) {
|
||||||
throw new Error('Missing web3-related environment variables')
|
throw new Error('Missing web3-related environment variables')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { chains, publicClient } = configureChains(
|
export const wagmiConfig = getDefaultConfig({
|
||||||
[mainnet, polygon, base, optimism],
|
|
||||||
[infuraProvider({ apiKey: PUBLIC_INFURA_ID }), publicProvider()]
|
|
||||||
)
|
|
||||||
|
|
||||||
export const { connectors } = getDefaultWallets({
|
|
||||||
appName: 'kremalicious.com',
|
appName: 'kremalicious.com',
|
||||||
projectId: PUBLIC_WALLETCONNECT_ID,
|
projectId: PUBLIC_WALLETCONNECT_ID,
|
||||||
chains
|
chains: [mainnet, polygon, base, optimism]
|
||||||
})
|
|
||||||
|
|
||||||
export const wagmiConfig = createConfig({
|
|
||||||
autoConnect: true,
|
|
||||||
connectors,
|
|
||||||
publicClient
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const theme: Theme = {
|
export const theme: Theme = {
|
||||||
|
@ -109,7 +109,7 @@ import CodeCopy from '@components/CopyCode.astro'
|
|||||||
|
|
||||||
<section class="section highlight" id="web3">
|
<section class="section highlight" id="web3">
|
||||||
<h4 class="titleCoin"><Wallet /> Web3 Wallet</h4>
|
<h4 class="titleCoin"><Wallet /> Web3 Wallet</h4>
|
||||||
<Web3 client:load />
|
<Web3 client:only="react" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
|
@ -1,19 +1,3 @@
|
|||||||
import { vi } from 'vitest'
|
|
||||||
|
|
||||||
export function configureChains() {
|
|
||||||
return { chains: [{}], provider: {} }
|
|
||||||
}
|
|
||||||
|
|
||||||
export const apiProvider = {
|
|
||||||
infura: vi.fn(),
|
|
||||||
alchemy: vi.fn(),
|
|
||||||
fallback: vi.fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDefaultWallets() {
|
|
||||||
return { connectors: [{}] }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ConnectButton() {
|
export function ConnectButton() {
|
||||||
return 'Connect Wallet'
|
return 'Connect Wallet'
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
export const prepareSendTransaction = async () => {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const prepareWriteContract = async () => {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendTransaction = async () => {
|
export const sendTransaction = async () => {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
@ -31,29 +31,14 @@ const mainnet = {
|
|||||||
serializers: undefined
|
serializers: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useNetwork() {
|
export function useChainId() {
|
||||||
return {
|
return 1
|
||||||
chain: mainnet
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useAccount() {
|
export function useAccount() {
|
||||||
return {
|
return {
|
||||||
address: '0x0000000000000000000000000000000000000000'
|
address: '0x0000000000000000000000000000000000000000',
|
||||||
}
|
chain: mainnet
|
||||||
}
|
|
||||||
|
|
||||||
export function usePrepareSendTransaction() {
|
|
||||||
return {
|
|
||||||
data: {
|
|
||||||
address: '0x0000000000000000000000000000000000000000'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePrepareContractWrite() {
|
|
||||||
return {
|
|
||||||
config: {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +99,9 @@ export function useProvider() {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const chain = mainnet
|
export function useConfig() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
export function createClient() {
|
export function createClient() {
|
||||||
return {
|
return {
|
||||||
|
Loading…
Reference in New Issue
Block a user