Skip to content

Commit

Permalink
feat: add vest all option in create vesting
Browse files Browse the repository at this point in the history
  • Loading branch information
JeanNeiverth committed Oct 11, 2024
1 parent d4dc945 commit 8817157
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 40 deletions.
6 changes: 5 additions & 1 deletion apps/create-vesting/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import { useGetHooksTransactions } from "#/hooks/useGetHooksTransactions";
import { useRouter } from "next/navigation";
import { useReadTokenContract } from "@bleu/cow-hooks-ui";
import { vestingFactoriesMapping } from "#/utils/vestingFactoriesMapping";
import { VestAllFromSwapCheckbox } from "#/components/VestAllFromSwapCheckbox";
import {
VestAllFromSwapCheckbox,
VestAllCheckbox,
} from "#/components/Checkboxes";
import { useTokenAmountTypeContext } from "#/context/TokenAmountType";

export default function Page() {
Expand Down Expand Up @@ -144,6 +147,7 @@ export default function Page() {
</div>
<br />
<VestAllFromSwapCheckbox />
<VestAllCheckbox />
<br />
</ContentWrapper>
<ButtonPrimary type="submit">
Expand Down
66 changes: 66 additions & 0 deletions apps/create-vesting/src/components/Checkboxes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useTokenAmountTypeContext } from "#/context/TokenAmountType";
import React, { useEffect } from "react";
import { useFormContext } from "react-hook-form";

export const FormCheckbox = ({
name,
state,
setState,
label,
}: {
name: string;
state: boolean;
setState: (state: boolean) => void;
label?: string;
}) => {
const { setValue } = useFormContext();

useEffect(() => {
console.log("state", state);
state ? setValue("amount", 1) : setValue("amount", 0);
setValue(name, state);
}, [state]);

return (
<div className="flex items-center space-x-2">
<input
type="checkbox"
id={name}
name={name}
checked={state}
onChange={() => setState(!state)}
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
<label
htmlFor={name}
className="text-sm font-medium text-gray-900 dark:text-gray-300"
>
{label}
</label>
</div>
);
};

export const VestAllFromSwapCheckbox = () => {
const { vestAllFromSwap, setVestAllFromSwap } = useTokenAmountTypeContext();
return (
<FormCheckbox
name="vestAllFromSwap"
state={vestAllFromSwap}
setState={setVestAllFromSwap}
label="Use all tokens from swap"
/>
);
};

export const VestAllCheckbox = () => {
const { vestAll, setVestAll } = useTokenAmountTypeContext();
return (
<FormCheckbox
name="vestAll"
state={vestAll}
setState={setVestAll}
label="Use all your tokens after swap"
/>
);
};
32 changes: 0 additions & 32 deletions apps/create-vesting/src/components/VestAllFromSwapCheckbox.tsx

This file was deleted.

20 changes: 19 additions & 1 deletion apps/create-vesting/src/context/TokenAmountType.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
"use client";

import { createContext, PropsWithChildren, useContext, useState } from "react";
import {
createContext,
PropsWithChildren,
useContext,
useEffect,
useState,
} from "react";

type TokenAmountType = {
vestAllFromSwap: boolean;
setVestAllFromSwap: (vestAllFromSwap: boolean) => void;
vestAll: boolean;
setVestAll: (vestAll: boolean) => void;
};

export const TokenAmountTypeContext = createContext({} as TokenAmountType);

export function TokenAmountTypeProvider({ children }: PropsWithChildren) {
const [vestAllFromSwap, setVestAllFromSwap] = useState<boolean>(false);
const [vestAll, setVestAll] = useState<boolean>(false);

useEffect(() => {
if (vestAllFromSwap) setVestAll(false);
}, [vestAllFromSwap]);
useEffect(() => {
if (vestAll) setVestAllFromSwap(false);
}, [vestAll]);

return (
<TokenAmountTypeContext.Provider
value={{
vestAllFromSwap,
setVestAllFromSwap,
vestAll,
setVestAll,
}}
>
{children}
Expand Down
69 changes: 69 additions & 0 deletions apps/create-vesting/src/hooks/useGetHooksInfoVestAll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {
TRANSACTION_TYPES,
TransactionFactory,
} from "@bleu/utils/transactionFactory";
import { useCallback } from "react";
import { GetHooksTransactionsParams } from "./useGetHooksTransactions";
import {
BaseTransaction,
IHooksInfo,
useIFrameContext,
} from "@bleu/cow-hooks-ui";
import { scaleToSecondsMapping } from "#/utils/scaleToSecondsMapping";
import { Address, maxUint256 } from "viem";

export const useGetHooksInfoVestAll = () => {
const { context, cowShedProxy } = useIFrameContext();

return useCallback(
async (
params: GetHooksTransactionsParams
): Promise<IHooksInfo | undefined> => {
const {
token,
vestingEscrowFactoryAddress,
formData: { period, periodScale, recipient },
} = params;

if (!context?.account || !cowShedProxy) return;

const periodInSeconds = period * scaleToSecondsMapping[periodScale];
const tokenAddress = token.address as Address;
const tokenSymbol = token.symbol ?? "";

const txs = await Promise.all([
// Approve create vesting
TransactionFactory.createRawTx(TRANSACTION_TYPES.ERC20_APPROVE, {
type: TRANSACTION_TYPES.ERC20_APPROVE,
token: tokenAddress,
spender: vestingEscrowFactoryAddress,
amount: maxUint256,
}),
// transfer from user to proxy and create vesting (weiroll)
TransactionFactory.createRawTx(
TRANSACTION_TYPES.CREATE_VESTING_WEIROLL,
{
type: TRANSACTION_TYPES.CREATE_VESTING_WEIROLL,
token: tokenAddress,
recipient: recipient,
cowShedProxy,
vestingDuration: BigInt(periodInSeconds),
vestingEscrowFactoryAddress: vestingEscrowFactoryAddress,
user: context.account,
}
),
]);

const permitData = [
{
tokenAddress: tokenAddress,
amount: maxUint256,
tokenSymbol: tokenSymbol,
},
];

return { txs, permitData };
},
[context?.account, cowShedProxy]
);
};
15 changes: 11 additions & 4 deletions apps/create-vesting/src/hooks/useGetHooksTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { IHooksInfo } from "@bleu/cow-hooks-ui";
import { Address } from "viem";
import { createVestingSchema } from "#/utils/schema";
import { Token } from "@uniswap/sdk-core";
import { useTokenAmountTypeContext } from "#/context/TokenAmountType";
import { useGetHooksInfoVestAllFromSwap } from "./useGetHooksInfoVestAllFromSwap";
import { useGetHooksInfoVestAll } from "./useGetHooksInfoVestAll";
import { useGetHooksInfoVestUserAmount } from "./useGetHooksInfoVestUserAmount";

export interface GetHooksTransactionsParams {
Expand All @@ -14,14 +14,21 @@ export interface GetHooksTransactionsParams {

export function useGetHooksTransactions() {
const getHooksInfoVestAllFromSwap = useGetHooksInfoVestAllFromSwap();
const getHooksInfoVestAll = useGetHooksInfoVestAll();
const getHooksInfoVestUserAmount = useGetHooksInfoVestUserAmount();

return async (
params: GetHooksTransactionsParams
): Promise<IHooksInfo | undefined> => {
const hooksInfo = params.formData.vestAllFromSwap
? await getHooksInfoVestAllFromSwap(params)
: await getHooksInfoVestUserAmount(params);
const {
formData: { vestAll, vestAllFromSwap },
} = params;

const hooksInfo = vestAll
? await getHooksInfoVestAll(params)
: vestAllFromSwap
? await getHooksInfoVestAllFromSwap(params)
: getHooksInfoVestUserAmount(params);

if (!hooksInfo) throw new Error("Error encoding transactions");

Expand Down
1 change: 1 addition & 0 deletions apps/create-vesting/src/utils/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const createVestingSchema = z.object({
.number({ message: "Invalid period" })
.gt(0, "Period must be greater than 0"),
vestAllFromSwap: z.boolean(),
vestAll: z.boolean(),
});

export type CreateVestingFormData = typeof createVestingSchema._type;
20 changes: 18 additions & 2 deletions packages/utils/transactionFactory/vestingEscrowFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface CreateVestingWeirollArgs extends BaseArgs {
recipient: Address;
vestingDuration: bigint;
vestingEscrowFactoryAddress: Address;
amount?: bigint;
user?: Address;
}

export class CreateVestingWeirollCreator
Expand All @@ -39,9 +39,25 @@ export class CreateVestingWeirollCreator
);

const amount = planner.add(
tokenWeirollContract.balanceOf(args.cowShedProxy)
// if user is passed, it means it is a Vest All operation,
// so the user's balance will be read instead of proxy's
tokenWeirollContract.balanceOf(args.user ?? args.cowShedProxy)
);

if (args.user) {
const tokenWeirollContractCall = weiroll.Contract.createContract(
new Contract(args.token, erc20Abi),
CommandFlags.CALL
);
planner.add(
tokenWeirollContractCall.transferFrom(
args.user,
args.cowShedProxy,
amount
)
);
}

planner.add(
vestingEscrowContract.deploy_vesting_contract(
args.token,
Expand Down

0 comments on commit 8817157

Please sign in to comment.