Skip to content

Commit

Permalink
Merge branch 'main' into jean/cow-412-placeholder-cow-amm-deposit-hoo…
Browse files Browse the repository at this point in the history
…k-review
  • Loading branch information
JeanNeiverth committed Oct 24, 2024
1 parent 43b0976 commit 41e24ef
Show file tree
Hide file tree
Showing 62 changed files with 810 additions and 476 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm biome check
pnpm biome check .
18 changes: 9 additions & 9 deletions apps/create-vesting/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@
}
],
"orientation": "portrait",
"name": "Create Vesting",
"short_name": "Create Vesting",
"name": "Create LlamaPay Vesting",
"short_name": "Create LlamaPay Vesting",
"start_url": ".",
"theme_color": "#ffffff",
"cow_hook_dapp": {
"id": "9da82fb07aa925c1a83fd0a97957d03a8787c6bd115e247784f97fcedb243bf7",
"name": "Create Vesting",
"id": "a316488cecc23fde8c39d3e748e0cb12bd4d18305826d36576d4bba74bd97baf",
"name": "Create LlamaPay Vesting",
"descriptionShort": "Create a LlamaPay vesting contract",
"description": "Create Vesting is a powerful hook designed to streamline the process of setting up a LlamaPay vesting contract right after your swap.",
"description": "This hook allows you to easily set up vesting contracts with LlamaPay. Enter the recipient’s address or ENS name, then choose how much to transfer: the token buy will be automatically detected by the hook and the contracts will be linked to your LlamaPay dashboard for seamless tracking.",
"version": "0.0.1",
"website": "https://github.com/bleu/cow-hooks-dapps",
"image": "http://127.0.0.1:3000/llama-pay-icon.png",
"walletCompatibility": ["EOA", "Smart contract"],
"website": "https://llamapay.io/vesting",
"image": "https://cow-hooks-dapps-create-vesting.vercel.app/llama-pay-icon.png",
"walletCompatibility": ["EOA"],
"conditions": {
"position": "post",
"smartContractWalletSupported": true
"smartContractWalletSupported": false
}
}
}
12 changes: 4 additions & 8 deletions apps/create-vesting/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import "@bleu/cow-hooks-ui/global.css";
import { IFrameContextProvider, Scrollbar } from "@bleu/cow-hooks-ui";
import { RootLayout } from "@bleu/cow-hooks-ui";
import Head from "next/head";
import type * as React from "react";
import { FormContextProvider } from "#/context/form";
Expand All @@ -16,15 +16,11 @@ export default function Layout({ children }: { children: React.ReactNode }) {
<Head>
<link rel="manifest" href="/manifest.json" />
</Head>
<IFrameContextProvider>
<RootLayout>
<TokenContextProvider>
<body className="bg-transparent">
<FormContextProvider>
<Scrollbar>{children}</Scrollbar>
</FormContextProvider>
</body>
<FormContextProvider>{children}</FormContextProvider>
</TokenContextProvider>
</IFrameContextProvider>
</RootLayout>
</html>
);
}
100 changes: 39 additions & 61 deletions apps/create-vesting/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
"use client";

import {
ButtonPrimary,
ClipBoardButton,
type HookDappContextAdjusted,
Info,
Spinner,
Wrapper,
useIFrameContext,
} from "@bleu/cow-hooks-ui";
import { Info, Spinner, useIFrameContext } from "@bleu/cow-hooks-ui";
import { useCallback, useState } from "react";
import { useFormContext, useWatch } from "react-hook-form";
import { useFormContext, useFormState, useWatch } from "react-hook-form";

import { ALL_SUPPORTED_CHAIN_IDS } from "@cowprotocol/cow-sdk";
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
import { AmountInput } from "#/components/AmountInput";
import { Button } from "#/components/Button";
import { InfoContent } from "#/components/InfoContent";
import { PeriodInput } from "#/components/PeriodInput";
import { RecipientInput } from "#/components/RecipientInput";
import { VestAllFromAccountCheckbox } from "#/components/VestAllFromAccountCheckbox";
Expand All @@ -23,19 +16,20 @@ import { VestUserInputCheckbox } from "#/components/VestUserInputCheckbox";
import { useTokenContext } from "#/context/token";
import { useFormatVariables } from "#/hooks/useFormatVariables";
import { decodeCalldata } from "#/utils/decodeCalldata";
import type { CreateVestingFormData } from "#/utils/schema";

export default function Page() {
const { context, publicClient } = useIFrameContext();
const [isEditHookLoading, setIsEditHookLoading] = useState(true);

const { token } = useTokenContext();

const { control, setValue } = useFormContext();
const { control, setValue } = useFormContext<CreateVestingFormData>();
const { isSubmitting, isSubmitSuccessful } = useFormState({ control });

const vestUserInput = useWatch({ control, name: "vestUserInput" });
const vestAllFromSwap = useWatch({ control, name: "vestAllFromSwap" });
const vestAllFromAccount = useWatch({ control, name: "vestAllFromAccount" });
const amount = useWatch({ control, name: "amount" });
const recipient = useWatch({ control, name: "recipient" });

const {
userBalanceFloat,
Expand Down Expand Up @@ -94,15 +88,23 @@ export default function Page() {
);

if (!context.account)
return <span className="mt-10 text-center">Connect your wallet first</span>;
return (
<span className="block w-full mt-10 text-center">
Connect your wallet first
</span>
);

if (!context?.orderParams?.buyTokenAddress)
if (!context?.orderParams?.buyAmount || !context?.orderParams?.buyAmount)
return (
<span className="mt-10 text-center">Provide a buy token in swap</span>
<span className="block w-full mt-10 text-center">
Provide a buy token and amount in swap
</span>
);

if (!ALL_SUPPORTED_CHAIN_IDS.includes(context.chainId)) {
return <span className="mt-10 text-center">Unsupported chain</span>;
return (
<span className="block w-full mt-10 text-center">Unsupported chain</span>
);
}

const amountPreview = vestAllFromSwap
Expand All @@ -118,9 +120,18 @@ export default function Page() {
!!allAfterSwapFloat &&
amount > allAfterSwapFloat;

const buttonDisabled =
isOutOfFunds ||
!recipient ||
(!amount && vestUserInput) ||
isSubmitting ||
isSubmitSuccessful;

const isBuildingHook = isSubmitting || isSubmitSuccessful;

return (
<Wrapper>
<div className="flex flex-col flex-grow py-4 gap-4 items-start justify-start text-center">
<div className="flex flex-col flex-wrap w-full flex-grow gap-4 mb-[-16px]">
<div className="w-full flex flex-col flex-grow gap-4 items-start justify-start text-center">
<RecipientInput />
<PeriodInput />
<AmountInput
Expand All @@ -133,51 +144,18 @@ export default function Page() {
userBalanceFloat={userBalanceFloat}
/>
<div className="flex flex-col gap-y-2">
<VestUserInputCheckbox />
<VestAllFromSwapCheckbox />
<VestAllFromAccountCheckbox />
<VestUserInputCheckbox />
</div>
</div>
<Info content={<InfoContent />} />
<ButtonPrimary type="submit" disabled={isOutOfFunds}>
<ButtonText context={context} isOutOfFunds={isOutOfFunds} />
</ButtonPrimary>
</Wrapper>
);
}

const InfoContent = () => {
return (
<span className="cursor-default">
To access Vesting Post-hook contract after swap, connect with the
recipient wallet at{" "}
<ClipBoardButton
buttonText="llamapay.io/vesting"
contentToCopy="https://llamapay.io/vesting"
className="flex items-center justify-center gap-1 cursor-pointer"
<Button
context={context}
isOutOfFunds={isOutOfFunds}
isBuildingHook={isBuildingHook}
disabled={buttonDisabled}
/>
</span>
</div>
);
};

const ButtonText = ({
context,
isOutOfFunds,
}: { context: HookDappContextAdjusted; isOutOfFunds: boolean }) => {
if (isOutOfFunds)
return (
<span className="flex items-center justify-center gap-2">
<ExclamationTriangleIcon className="w-6 h-6" />
You won't have enough funds
</span>
);

if (context?.hookToEdit && context?.isPreHook)
return <span>Update Pre-hook</span>;
if (context?.hookToEdit && !context?.isPreHook)
return <span>Update Post-hook</span>;
if (!context?.hookToEdit && context?.isPreHook)
return <span>Add Pre-hook</span>;
if (!context?.hookToEdit && !context?.isPreHook)
return <span>Add Post-hook</span>;
};
}
4 changes: 2 additions & 2 deletions apps/create-vesting/src/app/signing/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function Page() {

const cowShedCall = await cowShedSignature(txs);
if (!cowShedCall) throw new Error("Error signing hooks");
submitHook({
await submitHook({
target: cowShed.getFactoryAddress(),
callData: cowShedCall,
});
Expand Down Expand Up @@ -96,7 +96,7 @@ export default function Page() {
...permitSteps,
{
label: "Approve hooks",
description: "Approve proxy to execute the hooks in behalf of you",
description: "Approve proxy to execute the hooks on your behalf",
id: "approve-hooks",
callback: cowShedCallback,
},
Expand Down
1 change: 1 addition & 0 deletions apps/create-vesting/src/components/AmountInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const AmountInput = ({
name="amount"
type="number"
step={`0.${"0".repeat(token?.decimals ? token?.decimals - 1 : 8)}1`}
max="1000000000000"
token={token}
label="Vesting Amount"
placeholder="0.0"
Expand Down
61 changes: 61 additions & 0 deletions apps/create-vesting/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
ButtonPrimary,
type HookDappContextAdjusted,
} from "@bleu/cow-hooks-ui";
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";

export const Button = ({
context,
isOutOfFunds,
isBuildingHook,
disabled,
}: {
context: HookDappContextAdjusted;
isOutOfFunds: boolean;
isBuildingHook: boolean;
disabled: boolean;
}) => {
return (
<ButtonPrimary type="submit" disabled={disabled}>
<ButtonText
context={context}
isOutOfFunds={isOutOfFunds}
isBuildingHook={isBuildingHook}
/>
</ButtonPrimary>
);
};

const ButtonText = ({
context,
isOutOfFunds,
isBuildingHook,
}: {
context: HookDappContextAdjusted;
isOutOfFunds: boolean;
isBuildingHook: boolean;
}) => {
if (isOutOfFunds)
return (
<span className="flex items-center justify-center gap-2">
<ExclamationTriangleIcon className="w-6 h-6" />
You won't have enough funds
</span>
);

if (isBuildingHook)
return (
<span className="flex items-center justify-center gap-2">
Building post-hook...
</span>
);

if (context?.hookToEdit && context?.isPreHook)
return <span>Update pre-hook</span>;
if (context?.hookToEdit && !context?.isPreHook)
return <span>Update post-hook</span>;
if (!context?.hookToEdit && context?.isPreHook)
return <span>Add pre-hook</span>;
if (!context?.hookToEdit && !context?.isPreHook)
return <span>Add post-hook</span>;
};
19 changes: 19 additions & 0 deletions apps/create-vesting/src/components/InfoContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ArrowTopRightIcon } from "@radix-ui/react-icons";

export const InfoContent = () => {
return (
<span className="cursor-default">
To access Vesting Post-hook contract after swap, connect with the
recipient wallet at{" "}
<a
href="https://llamapay.io/vesting"
target="_blank"
rel="noreferrer"
className="text-color-link underline"
>
llamapay.io/vesting
<ArrowTopRightIcon className="size-4 shrink-0 inline" />
</a>
</span>
);
};
5 changes: 4 additions & 1 deletion apps/create-vesting/src/components/PeriodInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ export const PeriodInput = () => {
namePeriodValue="period"
namePeriodScale="periodScale"
type="number"
label="Lock-up Period"
min="0.000000001"
step="0.000000001"
max="1000000000000"
label="Vesting Period"
validation={{ valueAsNumber: true, required: true }}
onKeyDown={(e) =>
["e", "E", "+", "-"].includes(e.key) && e.preventDefault()
Expand Down
Loading

0 comments on commit 41e24ef

Please sign in to comment.