Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jean/cow 399 placeholder add weiroll on create vesting hook #32

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d08c224
chore: use IFrame context in create-vesting
JeanNeiverth Oct 4, 2024
bea91c2
feat: encode claim vesting hook with hardcoded token = wxdai
JeanNeiverth Oct 7, 2024
ee0ed92
feat: get real buying token from swap in create-vesting
JeanNeiverth Oct 7, 2024
a77121a
feat: add llama contract mapping by chainId
JeanNeiverth Oct 7, 2024
6ff0304
chore: move Spinner, WaitingSignature and SignatureSteps from withdra…
JeanNeiverth Oct 7, 2024
18f7f27
wip: permitting token in create-vesting hook
JeanNeiverth Oct 8, 2024
90169bc
chore: prefix UI possible review issues
JeanNeiverth Oct 8, 2024
df30f48
fix: small number token input create-vesting
JeanNeiverth Oct 9, 2024
c966b37
chore: remove cowswap generate permit function
JeanNeiverth Oct 9, 2024
b0c7588
chore: remove console.logs
JeanNeiverth Oct 9, 2024
471e1f5
fix: flow to make permittable tokens work in claim vesting
JeanNeiverth Oct 9, 2024
d08c87d
fix: make claim vesting work again for not permittable tokens
JeanNeiverth Oct 9, 2024
e818a2f
wip: add weiroll
JeanNeiverth Oct 9, 2024
a3fc01b
wip: add weiroll encoding
yvesfracari Oct 9, 2024
4650336
feat: add logic to always use delegate call in cowShed when its a wei…
JeanNeiverth Oct 10, 2024
f7b76c3
feat: make both user input and weiroll work at the same time
JeanNeiverth Oct 10, 2024
c277aae
chore: remove ERC20Permit 'transfer from'
JeanNeiverth Oct 11, 2024
0169cc7
fix: review issues
JeanNeiverth Oct 11, 2024
0ecc2fc
chore: update pnpm.lock
JeanNeiverth Oct 11, 2024
c3a9656
Merge with main to resolve conflicts
JeanNeiverth Oct 11, 2024
dbda669
Merge branch 'main' into jean/cow-399-placeholder-add-weiroll-on-crea…
JeanNeiverth Oct 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/create-vesting/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@
"@bleu/cow-hooks-ui": "workspace:*",
"@bleu/tsconfig": "workspace:*",
"@bleu/ui": "0.1.131",
"@bleu/utils": "workspace:*",
"@cowprotocol/cow-sdk": "^5.5.1",
"@cowprotocol/hook-dapp-lib": "1.0.0-RC1",
"@hookform/resolvers": "3.9.0",
"@radix-ui/react-icons": "1.3.0",
"@uniswap/sdk-core": "5.4.0",
"@weiroll/weiroll.js": "^0.3.0",
"babel-plugin-react-compiler": "0.0.0-experimental-6067d4e-20240923",
"ethers": "^5.7.2",
"next": "15.0.0-rc.0",
"react": "19.0.0-rc-e4953922-20240919",
"react-dom": "19.0.0-rc-e4953922-20240919",
Expand Down
12 changes: 9 additions & 3 deletions apps/create-vesting/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
import "#/global.css";
import Head from "next/head";
import type * as React from "react";
import { IFrameContextProvider } from "@bleu/cow-hooks-ui";
import { TokenAmountTypeProvider } from "#/context/TokenAmountType";

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className="h-full">
<Head>
<link rel="manifest" href="/manifest.json" />
</Head>
<body className="flex flex-col h-full font-sans font-normal">
{children}
</body>
<IFrameContextProvider>
<TokenAmountTypeProvider>
<body className="flex flex-col h-full font-sans font-normal">
{children}
</body>
</TokenAmountTypeProvider>
</IFrameContextProvider>
</html>
);
}
234 changes: 137 additions & 97 deletions apps/create-vesting/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,126 +1,166 @@
"use client";

import {
type CoWHookDappActions,
type HookDappContext,
initCoWHookDapp,
} from "@cowprotocol/hook-dapp-lib";

import {
Input,
PeriodWithScaleInput,
ButtonPrimary,
ContentWrapper,
TokenAmountInput,
Wrapper,
HookDappContextAdjusted,
useIFrameContext,
Spinner,
} from "@bleu/cow-hooks-ui";
import { Token } from "@uniswap/sdk-core";

import { useEffect, useState } from "react";

import { useCallback, useMemo } from "react";
import { Form } from "@bleu/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";

import { createVestingSchema, periodScaleOptions } from "#/utils/schema";

//will be used
import { scaleToSecondsMapping } from "#/utils/scaleToSecondsMapping";
import {
CreateVestingFormData,
createVestingSchema,
periodScaleOptions,
} from "#/utils/schema";

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 { useTokenAmountTypeContext } from "#/context/TokenAmountType";

export default function Page() {
const [actions, setActions] = useState<CoWHookDappActions | null>(null);
const [context, setContext] = useState<HookDappContext | null>(null);
const { vestAllFromSwap } = useTokenAmountTypeContext();
const { context, setHookInfo } = useIFrameContext();
const router = useRouter();

const isDarkMode = context?.isDarkMode;
// will be used
const { account, chainId } = context || {};

const form = useForm<typeof createVestingSchema._type>({
const form = useForm<CreateVestingFormData>({
resolver: zodResolver(createVestingSchema),
defaultValues: {
period: 1,
periodScale: "Day",
vestAllFromSwap: false,
},
});

const { handleSubmit } = form;

useEffect(() => {
const { actions } = initCoWHookDapp({ onContext: setContext });
setActions(actions);
}, []);

useEffect(() => {
const newTheme = isDarkMode ? "dark" : "light";
document.documentElement.setAttribute("data-theme", newTheme);
}, [isDarkMode]);

const addHook = () => {
if (!actions) return;

const hook = {
target: "",
callData: "",
gasLimit: "",
};
// will be used
// if (context?.hookToEdit) {
// actions.editHook({ hook, uuid: context.hookToEdit.uuid });
// } else {
// actions.addHook({ hook });
// }
};

function onSubmit(data: typeof createVestingSchema._type) {
if (!context) return;
console.log("data", data);
addHook();
}
const getHooksTransactions = useGetHooksTransactions();
const tokenAddress = context?.orderParams?.buyTokenAddress as
| `0x${string}`
| undefined;

const { tokenSymbol, tokenDecimals } = useReadTokenContract({ tokenAddress });

const token = useMemo(
() =>
context?.chainId && tokenAddress && tokenDecimals
? new Token(context.chainId, tokenAddress, tokenDecimals, tokenSymbol)
: undefined,
[context?.chainId, tokenAddress, tokenDecimals]
);

const vestingEscrowFactoryAddress = useMemo(() => {
return context?.chainId
? vestingFactoriesMapping[context.chainId]
: undefined;
}, [context?.chainId]);

const onSubmitCallback = useCallback(
async (data: CreateVestingFormData) => {
if (!context || !token || !vestingEscrowFactoryAddress) return;
const hookInfo = await getHooksTransactions({
token,
vestingEscrowFactoryAddress,
formData: data,
});
if (!hookInfo) return;
setHookInfo(hookInfo);
router.push("/signing");
},
[context?.account, token, vestingEscrowFactoryAddress, vestAllFromSwap]
);

const onSubmit = useMemo(
() => form.handleSubmit(onSubmitCallback),
[form, onSubmitCallback]
);

if (!context)
return (
<div className="h-full flex items-center justify-center">
<Spinner />
</div>
);

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

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

return (
<>
{context && (
<Form {...form} className="contents">
<Wrapper>
<ContentWrapper>
<Input
name="recipient"
label="Recipient"
placeholder="0xabc..."
autoComplete="off"
className="h-12 p-2.5 rounded-xl bg-color-paper-darker border-none placeholder:opacity-100"
/>
<br />
<div className="flex gap-4 w-full">
<PeriodWithScaleInput
periodScaleOptions={periodScaleOptions}
namePeriodValue="period"
namePeriodScale="periodScale"
label="Period"
validation={{ valueAsNumber: true, required: true }}
onKeyDown={(e) =>
["e", "E", "+", "-"].includes(e.key) && e.preventDefault()
}
/>
<TokenAmountInput
name="amount"
tokenSymbol="ETH"
label="Amount"
placeholder="0.0"
autoComplete="off"
validation={{ valueAsNumber: true, required: true }}
onKeyDown={(e) =>
["e", "E", "+", "-"].includes(e.key) && e.preventDefault()
}
/>
</div>
<br />
</ContentWrapper>
<ButtonPrimary type="submit" onClick={handleSubmit(onSubmit)}>
<span>{context?.hookToEdit ? "Edit Hook" : "Add hook"}</span>
</ButtonPrimary>
</Wrapper>
</Form>
)}
</>
<Form {...form} onSubmit={onSubmit} className="contents">
<Wrapper>
<ContentWrapper>
<Input
name="recipient"
label="Recipient"
placeholder="0xabc..."
autoComplete="off"
className="h-12 p-2.5 rounded-xl bg-color-paper-darker border-none placeholder:opacity-100"
/>
<br />
<div className="flex flex-col w-full xsm:gap-4 xsm:flex-row">
<PeriodWithScaleInput
periodScaleOptions={periodScaleOptions}
namePeriodValue="period"
namePeriodScale="periodScale"
type="number"
step="0.0000001"
label="Period"
validation={{ valueAsNumber: true, required: true }}
onKeyDown={(e) =>
["e", "E", "+", "-"].includes(e.key) && e.preventDefault()
}
/>
<br className="xsm:h-0 xsm:w-0" />
<TokenAmountInput
name="amount"
type="number"
step={`0.${"0".repeat(tokenDecimals ? tokenDecimals - 1 : 8)}1`}
token={token}
label="Amount"
placeholder="0.0"
autoComplete="off"
disabled={vestAllFromSwap}
validation={{ valueAsNumber: true, required: true }}
onKeyDown={(e) =>
["e", "E", "+", "-"].includes(e.key) && e.preventDefault()
}
/>
</div>
<br />
JeanNeiverth marked this conversation as resolved.
Show resolved Hide resolved
<VestAllFromSwapCheckbox />
<br />
</ContentWrapper>
<ButtonPrimary type="submit">
<ButtonText context={context} />
</ButtonPrimary>
</Wrapper>
</Form>
);
}

const ButtonText = ({ context }: { context: HookDappContextAdjusted }) => {
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>;
};
Loading
Loading