Skip to content

Commit

Permalink
rename join to add liquidity and exit to remove liquidity
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPereira committed Jun 14, 2024
1 parent 8041fba commit 7a2d039
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 137 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ ETHERSCAN_API_KEY=...
SEPOLIA_RPC_URL=...
```

- The `DEPLOYER_PRIVATE_KEY` must start with `0x` and will be referred to as 'DEPLOYER' throughout this README.
- The `DEPLOYER_PRIVATE_KEY` must start with `0x` and will be referred to as 'DEPLOYER' throughout this README.
- The `ETHERSCAN_API_KEY` is used to conveniently verify contracts from the command line with `yarn verify`
- The `SEPOLIA_RPC_URL` facilitates running a local fork and sending transactions to sepolia testnet

Expand Down Expand Up @@ -201,23 +201,23 @@ https://github.com/Dev-Rel-as-a-Service/scaffold-balancer-v3/assets/73561520/cc3
### 🚰 1.2 Use Your Pool
Connect the account you specified in the `.env` file using your favorite wallet extension and start splashing around in your pool with swaps, joins, and exits!
Connect the account you specified in the `.env` file using your favorite wallet extension and start splashing around in your pool by swapping, adding liquidity, and removing liquidity!
<details><summary><strong>👀 Swap Preview</strong></summary>
![Swap](https://github.com/Dev-Rel-as-a-Service/scaffold-balancer-v3/assets/73561520/64629016-5bb5-40ce-a3bd-2e421000b33d)
</details>
<details><summary><strong>👀 Join Preview</strong></summary>
<details><summary><strong>👀 Add Liquidity Preview</strong></summary>
![Join](https://github.com/Dev-Rel-as-a-Service/scaffold-balancer-v3/assets/73561520/cf8dc531-d98b-49fa-9195-ec86d7018e09)
![Add Liquidity](https://github.com/Dev-Rel-as-a-Service/scaffold-balancer-v3/assets/73561520/cf8dc531-d98b-49fa-9195-ec86d7018e09)
</details>
<details><summary><strong>👀 Exit Preview</strong></summary>
<details><summary><strong>👀 Remove Liquidity Preview</strong></summary>
![Exit](https://github.com/Dev-Rel-as-a-Service/scaffold-balancer-v3/assets/73561520/3604dbfb-fea2-414f-8e62-c01dc12cc691)
![Remove Liquidity](https://github.com/Dev-Rel-as-a-Service/scaffold-balancer-v3/assets/73561520/3604dbfb-fea2-414f-8e62-c01dc12cc691)
</details>
Expand Down
10 changes: 5 additions & 5 deletions packages/nextjs/app/pools/_components/PoolActions.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { useState } from "react";
import { ExitForm, JoinForm, SwapForm } from "./actions";
import { AddLiquidityForm, RemoveLiquidityForm, SwapForm } from "./actions";
import { type Pool } from "~~/hooks/balancer/types";
import { type RefetchPool } from "~~/hooks/balancer/usePoolContract";

type Action = "Swap" | "Join" | "Exit";
type Action = "Swap" | "AddLiquidity" | "RemoveLiquidity";

export interface PoolActionsProps {
pool: Pool;
refetchPool: RefetchPool;
}

/**
* Allow user to perform swap, join, and exit transactions with a pool
* Allow user to swap, add liquidity, and remove liquidity from a pool
*/
export const PoolActions: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
const [activeTab, setActiveTab] = useState<Action>("Swap");

const tabs = {
Swap: <SwapForm pool={pool} refetchPool={refetchPool} />,
Join: <JoinForm pool={pool} refetchPool={refetchPool} />,
Exit: <ExitForm pool={pool} refetchPool={refetchPool} />,
AddLiquidity: <AddLiquidityForm pool={pool} refetchPool={refetchPool} />,
RemoveLiquidity: <RemoveLiquidityForm pool={pool} refetchPool={refetchPool} />,
};

return (
Expand Down
12 changes: 6 additions & 6 deletions packages/nextjs/app/pools/_components/UserLiquidity.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { type TokenAmount } from "@balancer/sdk";
import { useAccount } from "wagmi";
import { useExit } from "~~/hooks/balancer/";
import { useRemoveLiquidity } from "~~/hooks/balancer/";
import { type Pool } from "~~/hooks/balancer/types";
import { formatToHuman } from "~~/utils/formatToHuman";

Expand All @@ -12,20 +12,20 @@ export const UserLiquidity = ({ pool }: { pool: Pool }) => {
const [expectedAmountsOut, setExpectedAmountsOut] = useState<TokenAmount[] | undefined>();

const { isConnected } = useAccount();
const { queryExit } = useExit(pool);
const { queryRemoveLiquidity } = useRemoveLiquidity(pool);

useEffect(() => {
async function fetchExitQuery() {
async function sendQuery() {
if (pool.userBalance > 0n) {
const { expectedAmountsOut } = await queryExit(pool.userBalance);
const { expectedAmountsOut } = await queryRemoveLiquidity(pool.userBalance);
setExpectedAmountsOut(expectedAmountsOut);
} else {
setExpectedAmountsOut(undefined);
}
}
fetchExitQuery();
sendQuery();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pool.userBalance]); // excluded queryExit from deps array because it causes infinite re-renders
}, [pool.userBalance]); // excluded queryRemoveLiquidity from deps array because it causes infinite re-renders

// only render the component if the pool is initialized and the user is connected
if (!isConnected || !pool?.poolConfig?.isPoolInitialized) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,37 @@ import { InputAmount } from "@balancer/sdk";
import { formatUnits, parseAbi, parseUnits } from "viem";
import { useContractEvent, usePublicClient, useWalletClient } from "wagmi";
import abis from "~~/contracts/abis";
import { useJoin } from "~~/hooks/balancer/";
import { QueryJoinResponse, QueryPoolActionError } from "~~/hooks/balancer/types";
import { useAddLiquidity } from "~~/hooks/balancer/";
import { QueryAddLiquidityResponse, QueryPoolActionError } from "~~/hooks/balancer/types";
import { useTransactor } from "~~/hooks/scaffold-eth";
import { formatToHuman } from "~~/utils/formatToHuman";

/**
* 1. Query the results of join transaction
* 2. User approves the vault for the tokens used in the join transaction (if necessary)
* 3. User sends transaction to join the pool
* 1. Query adding some amount of liquidity to the pool
* 2. Approve the Balancer vault to spend the tokens to be used in the transaction (if necessary)
* 3. Send transaction to add liquidity to the pool
* 4. Display the transaction results to the user
*/
export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
export const AddLiquidityForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
const initialTokenInputs = pool.poolTokens.map(token => ({
address: token.address as `0x${string}`,
decimals: token.decimals,
rawAmount: 0n,
}));
const [tokensToApprove, setTokensToApprove] = useState<InputAmount[]>([]);
const [tokenInputs, setTokenInputs] = useState<InputAmount[]>(initialTokenInputs);
const [queryResponse, setQueryResponse] = useState<QueryJoinResponse | null>(null);
const [queryResponse, setQueryResponse] = useState<QueryAddLiquidityResponse | null>(null);
const [sufficientAllowances, setSufficientAllowances] = useState(false);
const [queryError, setQueryError] = useState<QueryPoolActionError>();
const [isApproving, setIsApproving] = useState(false);
const [isQuerying, setIsQuerying] = useState(false);
const [isJoining, setIsJoining] = useState(false);
const [joinReceipt, setJoinReceipt] = useState<any>(null);
const [isAddingLiquidity, setIsAddingLiquidity] = useState(false);
const [txReceipt, setTxReceipt] = useState<any>(null);

const { queryJoin, joinPool, allowances, refetchAllowances, tokenBalances } = useJoin(pool, tokenInputs);
const { queryAddLiquidity, addLiquidity, allowances, refetchAllowances, tokenBalances } = useAddLiquidity(
pool,
tokenInputs,
);
const writeTx = useTransactor(); // scaffold hook for tx status toast notifications
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();
Expand Down Expand Up @@ -59,7 +63,7 @@ export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
const handleInputChange = (index: number, value: string) => {
setQueryError(null);
setQueryResponse(null);
setJoinReceipt(null);
setTxReceipt(null);
const updatedTokens = tokenInputs.map((token, idx) => {
if (idx === index) {
return { ...token, rawAmount: parseUnits(value, token.decimals) };
Expand All @@ -69,11 +73,11 @@ export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
setTokenInputs(updatedTokens);
};

const handleQueryJoin = async () => {
const handlequeryAddLiquidity = async () => {
setQueryResponse(null);
setJoinReceipt(null);
setTxReceipt(null);
setIsQuerying(true);
const response = await queryJoin();
const response = await queryAddLiquidity();
if (response.error) {
setQueryError(response.error);
} else {
Expand Down Expand Up @@ -110,16 +114,16 @@ export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
});
};

const handleJoinPool = async () => {
const handleAddLiquidity = async () => {
try {
setIsJoining(true);
await joinPool();
setIsAddingLiquidity(true);
await addLiquidity();
refetchAllowances();
refetchPool();
} catch (e) {
console.error("error", e);
} finally {
setIsJoining(false);
setIsAddingLiquidity(false);
}
};

Expand All @@ -135,7 +139,7 @@ export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
rawAmount: log[0].args.value,
};

setJoinReceipt({ bptOut, transactionHash: log[0].transactionHash });
setTxReceipt({ bptOut, transactionHash: log[0].transactionHash });
},
});

Expand All @@ -159,9 +163,9 @@ export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
))}
</div>

{!expectedBptOut || (expectedBptOut && joinReceipt) ? (
{!expectedBptOut || (expectedBptOut && txReceipt) ? (
<PoolActionButton
onClick={handleQueryJoin}
onClick={handlequeryAddLiquidity}
isDisabled={isQuerying}
isFormEmpty={tokenInputs.every(token => token.rawAmount === 0n)}
>
Expand All @@ -172,16 +176,16 @@ export const JoinForm: React.FC<PoolActionsProps> = ({ pool, refetchPool }) => {
Approve
</PoolActionButton>
) : (
<PoolActionButton isDisabled={isJoining} onClick={handleJoinPool}>
<PoolActionButton isDisabled={isAddingLiquidity} onClick={handleAddLiquidity}>
Add Liquidity
</PoolActionButton>
)}

{joinReceipt && (
{txReceipt && (
<TransactionReceiptAlert
title="Actual BPT Out"
transactionHash={joinReceipt.transactionHash}
data={[joinReceipt.bptOut]}
transactionHash={txReceipt.transactionHash}
data={[txReceipt.bptOut]}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ interface PoolActionButtonProps {
}

/**
* Styled button for approve and join/swap/exit transactions
*
* Approve button is outlined styles
* Join/Swap/Exit buttons are solid styles
* Approve button is outlined style
* Swap, AddLiquidity, and RemoveLiquidity buttons are solid gradient style
*/
export const PoolActionButton: React.FC<PoolActionButtonProps> = ({ onClick, children, isDisabled, isFormEmpty }) => {
const outlined = `border border-neutral hover:bg-neutral hover:text-neutral-content`;
Expand Down
Loading

0 comments on commit 7a2d039

Please sign in to comment.