From b95c8f9d6b015e80d8046240aa13a03401d0e7d8 Mon Sep 17 00:00:00 2001 From: Kirill Klimenko Date: Tue, 26 Mar 2024 20:51:38 +0100 Subject: [PATCH] Cleanup and a bit of implementation refactoring --- .../proposals/new/CustomProposalSubmitter.tsx | 145 ++++++++---------- 1 file changed, 63 insertions(+), 82 deletions(-) diff --git a/src/pages/daos/[daoAddress]/proposals/new/CustomProposalSubmitter.tsx b/src/pages/daos/[daoAddress]/proposals/new/CustomProposalSubmitter.tsx index 8d4c80b188..f5414e87b3 100644 --- a/src/pages/daos/[daoAddress]/proposals/new/CustomProposalSubmitter.tsx +++ b/src/pages/daos/[daoAddress]/proposals/new/CustomProposalSubmitter.tsx @@ -1,11 +1,14 @@ import { Button } from '@chakra-ui/react'; +import { BigNumber } from 'ethers'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; -import { encodeFunctionData, erc20Abi } from 'viem'; +import { Address, encodeFunctionData, erc20Abi } from 'viem'; import { mainnet, sepolia } from 'viem/chains'; +import { useAccount } from 'wagmi'; import SablierBatchABI from '../../../../../assets/abi/SablierV2Batch.json'; import { DAO_ROUTES } from '../../../../../constants/routes'; import useSubmitProposal from '../../../../../hooks/DAO/proposal/useSubmitProposal'; +import { useFractal } from '../../../../../providers/App/AppProvider'; import { useNetworkConfig } from '../../../../../providers/NetworkConfig/NetworkConfigProvider'; import { ProposalExecuteData } from '../../../../../types'; @@ -16,6 +19,10 @@ export default function CustomProposalSubmitter({ values: any; daoAddress?: string; }) { + const { + governanceContracts: { votesTokenContractAddress }, + } = useFractal(); + const { address: account } = useAccount(); const { chainId } = useNetworkConfig(); const { submitProposal } = useSubmitProposal(); const navigate = useNavigate(); @@ -28,101 +35,71 @@ export default function CustomProposalSubmitter({ }; const handleSubmitProposal = () => { const { nonce, proposalMetadata } = values; - const submitProposalBasicProps = { - nonce, - pendingToastMessage: t('proposalCreatePendingToastMessage'), - successToastMessage: t('proposalCreateSuccessToastMessage'), - failedToastMessage: t('proposalCreateFailureToastMessage'), - successCallback, - }; const functionName = 'createWithMilestones'; + let recipient: string | undefined = undefined; + let sablierBatchAddress: Address | undefined = undefined; + let sablierLockupDynamicAddress: Address | undefined = undefined; + let tokenAddress: Address | undefined = undefined; + const totalAmount = '250000000000000000000000'; // 250K + let startDate: number | undefined = undefined; + let segments: [number | string, string, number][] = []; if (chainId === sepolia.id) { - const recipient = '0x2884b7Bf17Ca966bB2e4099bf384734a48885Df0'; - const sablierBatchAddress = '0xd2569DC4A58dfE85d807Dffb976dbC0a3bf0B0Fb'; // SablierV2Batch - const sablierLockupDynamicAddress = '0xc9940AD8F43aAD8e8f33A4D5dbBf0a8F7FF4429A'; // SablierV2LockupDynamic - const tokenAddress = '0xa60196673256ae375c8ce2bb6b404c07b6b4a56a'; // Test DAO token address - const startDate = Math.round(Date.now() / 1000); - - const sablierBatchData = [ - sablierLockupDynamicAddress, // Address of LockupDynamic contract. Will be called by batch internally to create streams - tokenAddress, // Address of token to stream - [ - [ - daoAddress, // Tokens sender. This address will be able to cancel the stream - startDate, // Start time - true, // Cancelable - is it possible to cancel this stream - false, // Transferable - is receiver able to transfer receiving rights to someone else - recipient, // Receiver of tokens through stream - 250000, // total amount of tokens sent - ['0x0000000000000000000000000000000000000000', 0], // Optional broker - [ - [0, '1000000000000000000', startDate], // First number represents amount of tokens denoted in units of token's decimals. Second number represents exponent, denoted as a fixed-point number. Third value is a Unix timestamp till when amount set in first value will be fully streamed - [250000, '1000000000000000000', startDate + 60 * 10], // For testing purpose - make the whole amount streamed at the start date + 10 minutes - ], // Array of segments, see explanation above. Additional explanation: https://github.com/sablier-labs/v2-core/blob/main/src/types/DataTypes.sol#L131-L140 - ], - ], + recipient = account!; + sablierBatchAddress = '0xd2569DC4A58dfE85d807Dffb976dbC0a3bf0B0Fb'; // SablierV2Batch on Sepolia + sablierLockupDynamicAddress = '0xc9940AD8F43aAD8e8f33A4D5dbBf0a8F7FF4429A'; // SablierV2LockupDynamic on Sepolia + tokenAddress = votesTokenContractAddress as Address; // DAO token address + startDate = Math.round(Date.now() / 1000) + 60 * 5; // 5 minutes from now + segments = [ + [0, '1000000000000000000', startDate + 60 * 10], // First number represents amount of tokens denoted in units of token's decimals. Second number represents exponent, denoted as a fixed-point number. Third value is a Unix timestamp till when amount set in first value will be fully streamed + [totalAmount, '1000000000000000000', startDate + 60 * 15], // For testing purpose - make the whole amount streamed at the start date + 10 minutes + ]; // Array of segments, see explanation above. Additional explanation: https://github.com/sablier-labs/v2-core/blob/main/src/types/DataTypes.sol#L131-L140 + } else if (chainId === mainnet.id) { + recipient = daoAddress!; // TODO: Change this. this will lead to stream tokens to itself + sablierBatchAddress = '0xEa07DdBBeA804E7fe66b958329F8Fa5cDA95Bd55'; // SablierV2Batch on Mainnet + sablierLockupDynamicAddress = '0x7CC7e125d83A581ff438608490Cc0f7bDff79127'; // SablierV2LockupDynamic on Mainnet + tokenAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; // Mainnet USDC address + startDate = 1711980240; // Unix timestamp + const segmentAmount = BigNumber.from(totalAmount).div(5).toNumber(); + segments = [ + [0, '1000000000000000000', 1714572239], + [segmentAmount, '1000000000000000000', 1714572240], + [0, '1000000000000000000', 1717250639], + [segmentAmount, '1000000000000000000', 1717250640], + [0, '1000000000000000000', 1719842639], + [segmentAmount, '1000000000000000000', 1719842640], + [0, '1000000000000000000', 1722521039], + [segmentAmount, '1000000000000000000', 1722521040], + [0, '1000000000000000000', 1725199439], + [segmentAmount, '1000000000000000000', 1725199440], ]; + } - const sablierBatchCalldata = encodeFunctionData({ - abi: SablierBatchABI, - functionName, - args: sablierBatchData, - }); - const tokenCalldata = encodeFunctionData({ - abi: erc20Abi, - functionName: 'approve', - args: [sablierBatchAddress, BigInt('1000000000000000000000000')], - }); - - const proposalData: ProposalExecuteData = { - targets: [tokenAddress, sablierBatchAddress], - values: [0, 0], - calldatas: [tokenCalldata, sablierBatchCalldata], - metaData: { - title: proposalMetadata.title, - description: proposalMetadata.description, - documentationUrl: proposalMetadata.documentationUrl, - }, - }; - submitProposal({ - ...submitProposalBasicProps, - proposalData, - }); - } else if (chainId === mainnet.id) { - const recipient = daoAddress; // TODO: Change this. this will lead to stream tokens to itself - const sablierBatchAddress = '0xEa07DdBBeA804E7fe66b958329F8Fa5cDA95Bd55'; - const sablierLockupDynamicAddress = '0x7CC7e125d83A581ff438608490Cc0f7bDff79127'; // SablierV2LockupDynamic - const tokenAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; // Mainnet USDC address - const startTime = 1711980240; // Unix timestamp + if ( + sablierLockupDynamicAddress && + sablierBatchAddress && + tokenAddress && + startDate && + recipient && + segments.length > 0 + ) { const sablierBatchData = [ sablierLockupDynamicAddress, tokenAddress, [ [ - // Note - the order of inputs while using SablierV2Batch is different from order when using SablierV2LockupDynamic daoAddress, // Tokens sender. This address will be able to cancel the stream - startTime, // Start time + startDate, // Start time true, // Cancelable - is it possible to cancel this stream false, // Transferable - is receiver able to transfer receiving rights to someone else recipient, // Receiver of tokens through stream - 25000000000, // total amount of tokens sent - ['0x0000000000000000000000000000000000000000', 0], - [ - [0, '1000000000000000000', 1714572239], - [5000000000, '1000000000000000000', 1714572240], - [0, '1000000000000000000', 1717250639], - [5000000000, '1000000000000000000', 1717250640], - [0, '1000000000000000000', 1719842639], - [5000000000, '1000000000000000000', 1719842640], - [0, '1000000000000000000', 1722521039], - [5000000000, '1000000000000000000', 1722521040], - [0, '1000000000000000000', 1725199439], - [5000000000, '1000000000000000000', 1725199440], - ], + totalAmount, // total amount of tokens sent + ['0x0000000000000000000000000000000000000000', 0], // Optional broker + segments, // Segments array of tuples ], ], ]; + const sablierBatchCalldata = encodeFunctionData({ abi: SablierBatchABI, functionName, @@ -131,7 +108,7 @@ export default function CustomProposalSubmitter({ const tokenCalldata = encodeFunctionData({ abi: erc20Abi, functionName: 'approve', - args: [sablierBatchAddress, BigInt('25000000000000000000000000000')], + args: [sablierBatchAddress, BigInt(totalAmount)], }); const proposalData: ProposalExecuteData = { targets: [tokenAddress, sablierBatchAddress], @@ -144,10 +121,14 @@ export default function CustomProposalSubmitter({ }, }; submitProposal({ - ...submitProposalBasicProps, + nonce, + pendingToastMessage: t('proposalCreatePendingToastMessage'), + successToastMessage: t('proposalCreateSuccessToastMessage'), + failedToastMessage: t('proposalCreateFailureToastMessage'), + successCallback, proposalData, }); } }; - return ; + return ; }