Skip to content

Commit

Permalink
trade: Implement Permit2
Browse files Browse the repository at this point in the history
  • Loading branch information
sehyunc committed Mar 9, 2024
1 parent 5573cac commit 23809b9
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 74 deletions.
120 changes: 73 additions & 47 deletions trade.renegade.fi/app/(desktop)/[base]/[quote]/deposit-button.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { ArrowForwardIcon } from "@chakra-ui/icons"
import { Button, useDisclosure } from "@chakra-ui/react"
import { Token } from "@renegade-fi/renegade-js"
import { useQueryClient } from '@tanstack/react-query'
import { useEffect } from 'react'
import { toast } from "sonner"
import { formatUnits, parseUnits } from "viem"
import { useAccount, useBlockNumber } from 'wagmi'

import { renegade } from "@/app/providers"
import { CreateStepper } from "@/components/steppers/create-stepper/create-stepper"
import { useDeposit } from "@/contexts/Deposit/deposit-context"
import { useRenegade } from "@/contexts/Renegade/renegade-context"
import { env } from "@/env.mjs"
import {
useReadErc20Allowance,
useReadErc20BalanceOf,
useWriteErc20Approve
useWriteErc20Approve,
} from "@/generated"
import { ArrowForwardIcon } from "@chakra-ui/icons"
import { Button, useDisclosure } from "@chakra-ui/react"
import { Token } from "@renegade-fi/renegade-js"
import { useQueryClient } from "@tanstack/react-query"
import { useEffect } from "react"
import { toast } from "sonner"
import {
parseUnits
} from "viem"
import { useAccount, useBlockNumber, useWalletClient } from "wagmi"

import { renegade } from "@/app/providers"
import { CreateStepper } from "@/components/steppers/create-stepper/create-stepper"
import { useButton } from "@/hooks/use-button"
import { stylusDevnetEc2 } from "@/lib/chain"
import { signPermit2 } from "@/lib/permit2"

const MAX_INT = BigInt(
"115792089237316195423570985008687907853269984665640564039457584007913129639935"
Expand All @@ -40,19 +44,24 @@ export default function DepositButton() {
const { address } = useAccount()

// Get L1 ERC20 balance
const { data: l1Balance, queryKey: l1BalanceQueryKey } = useReadErc20BalanceOf({
address: Token.findAddressByTicker(baseTicker) as `0x${string}`,
args: [address ?? "0x"],
})
const { data: l1Balance, queryKey: l1BalanceQueryKey } =
useReadErc20BalanceOf({
address: Token.findAddressByTicker(baseTicker) as `0x${string}`,
args: [address ?? "0x"],
})
// TODO: Adjust decimals
console.log("Balance on L1: ", formatUnits(l1Balance ?? BigInt(0), 18))
// console.log("Balance on L1: ", formatUnits(l1Balance ?? BigInt(0), 18))

// Get L1 ERC20 Allowance
const { data: allowance, queryKey: allowanceQueryKey } = useReadErc20Allowance({
address: Token.findAddressByTicker(baseTicker) as `0x${string}`,
args: [address ?? "0x", env.NEXT_PUBLIC_DARKPOOL_CONTRACT as `0x${string}`],
})
console.log(`${baseTicker} allowance: `, allowance)
const { data: allowance, queryKey: allowanceQueryKey } =
useReadErc20Allowance({
address: Token.findAddressByTicker(baseTicker) as `0x${string}`,
args: [
address ?? "0x",
env.NEXT_PUBLIC_PERMIT2_CONTRACT as `0x${string}`,
],
})
// console.log(`${baseTicker} allowance on Permit2 contract: `, allowance)

const queryClient = useQueryClient()
const { data: blockNumber } = useBlockNumber({ watch: true })
Expand All @@ -61,22 +70,16 @@ export default function DepositButton() {
queryClient.invalidateQueries({ queryKey: allowanceQueryKey })
}, [allowanceQueryKey, blockNumber, l1BalanceQueryKey, queryClient])


// L1 ERC20 Approval
const { writeContract: approve, status: approveStatus } = useWriteErc20Approve()
const { writeContract: approve, status: approveStatus } =
useWriteErc20Approve()

const { data: walletClient } = useWalletClient()

const hasRpcConnectionError = typeof allowance === "undefined"
console.log(
"🚀 ~ DepositButton ~ hasRpcConnectionError:",
hasRpcConnectionError
)
const hasInsufficientBalance = l1Balance
? l1Balance < parseUnits(baseTokenAmount, 18)
: false
console.log(
"🚀 ~ DepositButton ~ hasInsufficientBalance:",
hasInsufficientBalance
)
const needsApproval = allowance === BigInt(0) && approveStatus !== "success"

const isDisabled =
Expand All @@ -88,10 +91,45 @@ export default function DepositButton() {
if (!accountId) return
approve({
address: Token.findAddressByTicker(baseTicker) as `0x${string}`,
args: [env.NEXT_PUBLIC_DARKPOOL_CONTRACT as `0x${string}`, MAX_INT],
args: [env.NEXT_PUBLIC_PERMIT2_CONTRACT as `0x${string}`, MAX_INT],
})
}

const handleSignAndDeposit = async () => {
if (!accountId || !walletClient) return
const token = new Token({ address: Token.findAddressByTicker(baseTicker) })
const amount = parseUnits(baseTokenAmount, 18)

// Generate Permit2 Signature
const { signature, nonce, deadline } = await signPermit2({
amount,
chainId: stylusDevnetEc2.id,
spender: env.NEXT_PUBLIC_DARKPOOL_CONTRACT as `0x${string}`,
permit2Address: env.NEXT_PUBLIC_PERMIT2_CONTRACT as `0x${string}`,
token,
walletClient,
})

// Deposit
await renegade.task
.deposit(
accountId,
token,
amount,
walletClient.account.address,
nonce,
deadline,
signature
)
.then(() =>
toast.message(`Started to deposit ${baseTokenAmount} ${baseTicker}`, {
description: "Check the history tab for the status of the task",
})
)
.catch((error) => toast.error(`Error depositing: ${error}`))
}


const handleClick = async () => {
if (shouldUse) {
buttonOnClick()
Expand All @@ -100,21 +138,9 @@ export default function DepositButton() {
} else if (needsApproval) {
handleApprove()
} else {
if (!accountId || !address) return
await renegade.task
.deposit(
accountId,
new Token({ address: Token.findAddressByTicker(baseTicker) }),
BigInt(baseTokenAmount),
address
)
.then(() =>
toast.message(`Started to deposit ${baseTokenAmount} ${baseTicker}`, {
description: "Check the history tab for the status of the task",
})
)
.catch((error) => toast.error(`Error depositing: ${error}`))
handleSignAndDeposit()
}

}

return (
Expand Down
54 changes: 31 additions & 23 deletions trade.renegade.fi/components/panels/wallets-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"use client"

import { useMemo } from "react"
import Image from "next/image"
import { useRouter } from "next/navigation"
import { ViewEnum, useApp } from "@/contexts/App/app-context"
import { useRenegade } from "@/contexts/Renegade/renegade-context"
import { TaskState } from "@/contexts/Renegade/types"
Expand All @@ -13,26 +16,24 @@ import {
import { Box, Button, Flex, Spacer, Spinner, Text } from "@chakra-ui/react"
import { Token, tokenMappings } from "@renegade-fi/renegade-js"
import { useModal as useModalConnectKit } from "connectkit"
import Image from "next/image"
import { useRouter } from "next/navigation"
import { useMemo } from "react"
import SimpleBar from "simplebar-react"
import { useAccount, useAccount as useAccountWagmi } from "wagmi"

import { ConnectWalletButton, SignInButton } from "@/app/(desktop)/main-nav"
import { Panel, expandedPanelWidth } from "@/components/panels/panels"
import { formatAmount } from "@/lib/utils"
import { useBalance } from "@/hooks/use-balance"
import { useTasks } from "@/hooks/use-tasks"
import { useUSDPrice } from "@/hooks/use-usd-price"

import { Panel, expandedPanelWidth } from "@/components/panels/panels"
import { ConnectWalletButton, SignInButton } from "@/app/(desktop)/main-nav"
import { renegade } from "@/app/providers"
import { useTasks } from "@/hooks/use-tasks"

import "simplebar-react/dist/simplebar.min.css"
import { toast } from "sonner"

interface TokenBalanceProps {
tokenAddr: string
userAddr?: string
amount: bigint
amount: string
}
function TokenBalance(props: TokenBalanceProps) {
const { tokenIcons } = useApp()
Expand All @@ -44,7 +45,7 @@ function TokenBalance(props: TokenBalanceProps) {
const ticker = Token.findTickerByAddress(`${props.tokenAddr}`)
const usdPrice = useUSDPrice(ticker, Number(props.amount))

const isZero = props.amount === BigInt(0)
const isZero = props.amount === "0"

return (
<Flex
Expand Down Expand Up @@ -108,9 +109,15 @@ function TokenBalance(props: TokenBalanceProps) {
address
)
.then(() =>
toast.message(`Started to withdraw 1 ${Token.findTickerByAddress(props.tokenAddr)}`, {
description: "Check the history tab for the status of the task",
})
toast.message(
`Started to withdraw 1 ${Token.findTickerByAddress(
props.tokenAddr
)}`,
{
description:
"Check the history tab for the status of the task",
}
)
)
.catch((error) => toast.error(`Error withdrawing: ${error}`))
}
Expand Down Expand Up @@ -179,19 +186,20 @@ function RenegadeWalletPanel(props: RenegadeWalletPanelProps) {
const balances = useBalance()
const { accountId } = useRenegade()

const formattedBalances = useMemo<Array<[string, bigint]>>(() => {
const wethAddress = Token.findAddressByTicker("WETH").replace("0x", "")
const usdcAddress = Token.findAddressByTicker("USDC").replace("0x", "")

const nonzero: Array<[string, bigint]> = Object.entries(balances).map(
([_, b]) => [b.mint.address, b.amount]
)
const placeholders: Array<[string, bigint]> = tokenMappings.tokens
const formattedBalances = useMemo(() => {
const nonzero = Object.entries(balances).map(([_, b]) => [
b.mint.address,
formatAmount(b.amount, new Token({ address: b.mint.address })),
])
const placeholders = tokenMappings.tokens
.filter((t) => !nonzero.some(([a]) => `0x${a}` === t.address))
.map((t) => [t.address.replace("0x", ""), BigInt(0)])
.map((t) => [t.address.replace("0x", ""), "0"])

const combined = [...nonzero, ...placeholders]

const wethAddress = Token.findAddressByTicker("WETH").replace("0x", "")
const usdcAddress = Token.findAddressByTicker("USDC").replace("0x", "")

combined.sort((a, b) => {
if (a[0] === wethAddress) return -1
if (b[0] === wethAddress) return 1
Expand Down Expand Up @@ -261,8 +269,8 @@ function RenegadeWalletPanel(props: RenegadeWalletPanelProps) {
{accountId
? "Deposit tokens into your Renegade Account to get started."
: address
? "Sign in to create a Renegade account and view your balances."
: "Connect your Ethereum wallet before signing in."}
? "Sign in to create a Renegade account and view your balances."
: "Connect your Ethereum wallet before signing in."}
</Text>
</Flex>
)
Expand Down
2 changes: 2 additions & 0 deletions trade.renegade.fi/env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const env = createEnv({
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: z.string().min(1),
NEXT_PUBLIC_INTERCOM_APP_ID: z.string().min(1),
NEXT_PUBLIC_DARKPOOL_CONTRACT: z.string().min(1),
NEXT_PUBLIC_PERMIT2_CONTRACT: z.string().nonempty()
},
// For Next.js >= 13.4.4, you only need to destructure client variables:
experimental__runtimeEnv: {
Expand All @@ -17,5 +18,6 @@ export const env = createEnv({
process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID,
NEXT_PUBLIC_INTERCOM_APP_ID: process.env.NEXT_PUBLIC_INTERCOM_APP_ID,
NEXT_PUBLIC_DARKPOOL_CONTRACT: process.env.NEXT_PUBLIC_DARKPOOL_CONTRACT,
NEXT_PUBLIC_PERMIT2_CONTRACT: process.env.NEXT_PUBLIC_PERMIT2_CONTRACT,
},
})
6 changes: 3 additions & 3 deletions trade.renegade.fi/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,6 @@ export const useWatchErc20Event = /*#__PURE__*/ createUseWatchContractEvent({
*/
export const useWatchErc20ApprovalEvent =
/*#__PURE__*/ createUseWatchContractEvent({
abi: erc20Abi,
eventName: 'Approval',
})
abi: erc20Abi,
eventName: 'Approval',
})
Loading

0 comments on commit 23809b9

Please sign in to comment.