Skip to content

Commit

Permalink
Update FE swaps to use permit2
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPereira committed Jun 27, 2024
1 parent 75c73c6 commit 9d4146e
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 32 deletions.
16 changes: 12 additions & 4 deletions packages/nextjs/app/pools/_components/actions/SwapForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export const SwapForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
refetchTokenInAllowance,
tokenInBalance,
refetchTokenInBalance,
approveAsync,
approveSpenderOnToken,
approveSpenderOnPermit2,
} = useSwap(pool, swapConfig);
const writeTx = useTransactor();

Expand Down Expand Up @@ -154,7 +155,14 @@ export const SwapForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
const handleApprove = async () => {
try {
setIsApproving(true);
await writeTx(approveAsync, {
await writeTx(approveSpenderOnToken, {
blockConfirmations: 1,
onBlockConfirmation: () => {
refetchTokenInAllowance();
setIsApproving(false);
},
});
await writeTx(approveSpenderOnPermit2, {
blockConfirmations: 1,
onBlockConfirmation: () => {
refetchTokenInAllowance();
Expand Down Expand Up @@ -227,8 +235,8 @@ export const SwapForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
tokenDropdownOpen={isTokenInDropdownOpen}
setTokenDropdownOpen={setTokenInDropdownOpen}
selectableTokens={pool.poolTokens.filter(token => token.symbol !== tokenIn.symbol)}
allowance={formatToHuman(tokenInAllowance ?? 0n, tokenIn.decimals)}
balance={formatToHuman(tokenInBalance ?? 0n, tokenIn.decimals)}
allowance={formatToHuman(tokenInAllowance, tokenIn.decimals)}
balance={formatToHuman(tokenInBalance, tokenIn.decimals)}
isHighlighted={queryResponse?.swapKind === SwapKind.GivenIn}
/>
<TokenField
Expand Down
64 changes: 42 additions & 22 deletions packages/nextjs/hooks/balancer/useSwap.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
import { useState } from "react";
import { Slippage, Swap, SwapBuildOutputExactIn, SwapBuildOutputExactOut, SwapKind, TokenAmount } from "@balancer/sdk";
import {
BALANCER_ROUTER,
PERMIT2,
Slippage,
Swap,
SwapBuildOutputExactIn,
SwapBuildOutputExactOut,
SwapKind,
TokenAmount,
erc20Abi,
permit2Abi,
} from "@balancer/sdk";
import { WriteContractResult } from "@wagmi/core";
import { parseAbi } from "viem";
import { zeroAddress } from "viem";
import { useContractRead, useContractWrite, useWalletClient } from "wagmi";
import { useTargetFork } from "~~/hooks/balancer";
import { Pool, QuerySwapResponse, SwapConfig, TransactionHash } from "~~/hooks/balancer/types";
import { useTransactor } from "~~/hooks/scaffold-eth";
import { MaxUint48, MaxUint160, MaxUint256 } from "~~/utils/constants";

type PoolSwapFunctions = {
querySwap: () => Promise<QuerySwapResponse>;
swap: () => Promise<TransactionHash>;
tokenInAllowance: bigint | undefined;
tokenInBalance: bigint | undefined;
tokenInAllowance: bigint;
tokenInBalance: bigint;
refetchTokenInAllowance: () => void;
refetchTokenInBalance: () => void;
approveAsync: () => Promise<WriteContractResult>;
approveSpenderOnToken: () => Promise<WriteContractResult>;
approveSpenderOnPermit2: () => Promise<WriteContractResult>;
};

/**
Expand All @@ -24,6 +37,7 @@ type PoolSwapFunctions = {
export const useSwap = (pool: Pool, swapConfig: SwapConfig): PoolSwapFunctions => {
const [call, setCall] = useState<SwapBuildOutputExactIn | SwapBuildOutputExactOut>();
const { data: walletClient } = useWalletClient();
const connectedAddress = walletClient?.account.address;
const { rpcUrl, chainId } = useTargetFork();
const writeTx = useTransactor();

Expand Down Expand Up @@ -111,7 +125,6 @@ export const useSwap = (pool: Pool, swapConfig: SwapConfig): PoolSwapFunctions =
to: call.to,
value: call.value,
});

const txHash = await writeTx(txHashPromise, { blockConfirmations: 1 });
if (!txHash) {
throw new Error("Transaction failed");
Expand All @@ -125,36 +138,43 @@ export const useSwap = (pool: Pool, swapConfig: SwapConfig): PoolSwapFunctions =
};

const { data: tokenInAllowance, refetch: refetchTokenInAllowance } = useContractRead({
address: tokenIn.address,
abi: parseAbi(["function allowance(address owner, address spender) returns (uint256)"]),
functionName: "allowance" as any, // ???
args: [
(walletClient?.account.address as `0x${string}`) || "0x0000000000000000000000000000000000000000",
pool.vaultAddress,
],
address: PERMIT2[chainId],
abi: permit2Abi,
functionName: "allowance",
args: [connectedAddress || zeroAddress, tokenIn.address, BALANCER_ROUTER[chainId]],
});

const { data: tokenInBalance, refetch: refetchTokenInBalance } = useContractRead({
address: tokenIn.address,
abi: parseAbi(["function balanceOf(address owner) returns (uint256)"]),
functionName: "balanceOf" as any, // ???
args: [(walletClient?.account.address as `0x${string}`) || "0x0000000000000000000000000000000000000000"],
abi: erc20Abi,
functionName: "balanceOf",
args: [connectedAddress || zeroAddress],
});

const { writeAsync: approveAsync } = useContractWrite({
// Max approve canonical Permit2 address to spend account's tokens
const { writeAsync: approveSpenderOnToken } = useContractWrite({
address: tokenIn.address,
abi: parseAbi(["function approve(address spender, uint256 amount) returns (bool)"]),
abi: erc20Abi,
functionName: "approve",
args: [PERMIT2[chainId], MaxUint256], // point this approval at permit2 contract
});

// Approve Router to spend account's tokens using Permit2
const { writeAsync: approveSpenderOnPermit2 } = useContractWrite({
address: PERMIT2[chainId],
abi: permit2Abi,
functionName: "approve",
args: [pool.vaultAddress, swapConfig.tokenIn.rawAmount],
args: [tokenIn.address, BALANCER_ROUTER[chainId], MaxUint160, MaxUint48],
});

return {
querySwap,
swap,
tokenInBalance,
tokenInAllowance,
tokenInBalance: tokenInBalance ? tokenInBalance : 0n,
tokenInAllowance: tokenInAllowance ? tokenInAllowance[0] : 0n,
refetchTokenInAllowance,
refetchTokenInBalance,
approveAsync,
approveSpenderOnToken,
approveSpenderOnPermit2,
};
};
2 changes: 1 addition & 1 deletion packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"dependencies": {
"@apollo/client": "^3.9.7",
"@balancer/sdk": "^0.16.0",
"@balancer/sdk": "^0.18.0",
"@ethersproject/providers": "^5.7.2",
"@heroicons/react": "^2.0.11",
"@rainbow-me/rainbowkit": "1.3.5",
Expand Down
3 changes: 3 additions & 0 deletions packages/nextjs/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const MaxUint256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
export const MaxUint160 = BigInt("0xffffffffffffffffffffffffffffffffffffffff");
export const MaxUint48 = Number("0xffffffffffff");
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,14 @@ __metadata:
languageName: node
linkType: hard

"@balancer/sdk@npm:^0.16.0":
version: 0.16.0
resolution: "@balancer/sdk@npm:0.16.0"
"@balancer/sdk@npm:^0.18.0":
version: 0.18.0
resolution: "@balancer/sdk@npm:0.18.0"
dependencies:
decimal.js-light: ^2.5.1
lodash.clonedeep: ^4.5.0
viem: ^2.12.1
checksum: 6929a8c95b7c10517e195d61906c7d9cf4360e3acdc2801d14ab2b4a53772460bf40019a682365b6bf9e4bcc53adc4f6a534a1eddcf9390691c30a91367b510d
checksum: d81b26ea912f81645dbe6ccbe42b6c7101d1af210d964c18cf3848bc6c5de7f9cd84da4c5275bd512181fd9d4f045eda67b8743f4571e12dfb6369cdd4d46334
languageName: node
linkType: hard

Expand Down Expand Up @@ -1576,7 +1576,7 @@ __metadata:
resolution: "@se-2/nextjs@workspace:packages/nextjs"
dependencies:
"@apollo/client": ^3.9.7
"@balancer/sdk": ^0.16.0
"@balancer/sdk": ^0.18.0
"@ethersproject/providers": ^5.7.2
"@heroicons/react": ^2.0.11
"@rainbow-me/rainbowkit": 1.3.5
Expand Down

0 comments on commit 9d4146e

Please sign in to comment.