From c8cb2987b2d617ece7161cb6bd89a47934af1aa0 Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 2 Oct 2024 12:42:55 +0100 Subject: [PATCH 01/15] Tighten up `BigIntInput` form value update logic. Add explicit doc --- .../formComponents/GuardDetails.tsx | 2 +- src/components/ui/forms/BigIntInput.tsx | 30 ++++++++++++++----- src/components/ui/modals/SendAssetsModal.tsx | 5 ++-- src/types/common.ts | 3 ++ 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/components/DaoCreator/formComponents/GuardDetails.tsx b/src/components/DaoCreator/formComponents/GuardDetails.tsx index 5a3079ccf1..6db5752328 100644 --- a/src/components/DaoCreator/formComponents/GuardDetails.tsx +++ b/src/components/DaoCreator/formComponents/GuardDetails.tsx @@ -153,7 +153,7 @@ function GuardDetails(props: ICreationStepProps) { { setFieldValue('freeze.freezeVotesThreshold', valuePair); }} diff --git a/src/components/ui/forms/BigIntInput.tsx b/src/components/ui/forms/BigIntInput.tsx index 7a2b9081e4..ed98e817e5 100644 --- a/src/components/ui/forms/BigIntInput.tsx +++ b/src/components/ui/forms/BigIntInput.tsx @@ -19,29 +19,30 @@ export interface BigIntInputProps min?: string; max?: string; maxValue?: bigint; - currentValue?: BigIntValuePair; + parentFormikValue?: BigIntValuePair; } /** * This component will add a chakra Input component that accepts and sets a bigint * * @param value input value to the control as a bigint. If undefined is set then the component will be blank. - * @param onChange event is raised whenever the component changes. Sends back a value / bigint pair. The value sent back is a string representation of the bigint as a decimal number. + * @param onChange event is raised whenever the component changes. Sends back a resulting `BigIntValuePair` from the new input. * @param decimalPlaces number of decimal places to be used to parse the value to set the bigint * @param min Setting a minimum value will reset the Input value to min when the component's focus is lost. Can set decimal number for minimum, but must respect the decimalPlaces value. * @param max Setting this will cause the value of the Input control to be reset to the maximum when a number larger than it is inputted. * @param maxValue The maximum value that can be inputted. This is used to set the max value of the Input control. - * @param currentValue This needs to be set to `values.yourFormValue` if the value of the Input control is changed outside of the component, for example via `setFieldValue`. This will update the value of the underlying Input control. + * @param parentFormikValue This needs to be set to `values.yourFormValue` if the value of the Input control is changed outside of the component, for example via `setFieldValue`. This will update the value of the underlying Input control. * @param ...rest component accepts all properties for Input and FormControl * @returns */ export function BigIntInput({ + // @todo `value` can most likely either be removed, or be used for what `parentFormikValue` is currently being used for. Currently it works as nothing more than an initial value. value, onChange, decimalPlaces = 18, min, max, maxValue, - currentValue, + parentFormikValue = { value: '', bigintValue: undefined }, ...rest }: BigIntInputProps) { const { t } = useTranslation('common'); @@ -147,10 +148,23 @@ export function BigIntInput({ // if the parent Formik value prop changes, need to update the value useEffect(() => { - if (!inputValue || inputValue === currentValue?.value) return; - if (currentValue?.bigintValue === 0n) setInputValue(''); - if (currentValue?.value !== inputValue) setInputValue(currentValue?.value || inputValue); - }, [currentValue, inputValue]); + + // If parentFormikValue is set to undefined, then the input should be blank + if (parentFormikValue === undefined) { + setInputValue(''); + return; + } + + // If parentFormikValue is the same as the input value, nothing needs to happen. + if (inputValue === parentFormikValue.value) return; + + // If parentFormikValue does not match the input value (likely because it was set outside of the input's onChange handler), + // then update the underlying input value so that the change is visible on the UI. + // But if parentFormikValue.value is false-y, default to whatever is in the input. + if (parentFormikValue.value !== inputValue) { + setInputValue(parentFormikValue?.value || inputValue); + } + }, [parentFormikValue, inputValue]); // if the decimalPlaces change, need to update the value useEffect(() => { diff --git a/src/components/ui/modals/SendAssetsModal.tsx b/src/components/ui/modals/SendAssetsModal.tsx index eba43aa791..eafb35c6df 100644 --- a/src/components/ui/modals/SendAssetsModal.tsx +++ b/src/components/ui/modals/SendAssetsModal.tsx @@ -136,7 +136,8 @@ export function SendAssetsModal({ iconSize="1.5rem" icon={} onChange={e => { - setFieldValue('inputAmount', { value: '0', bigintValue: 0n }); + // New asset selected. First reset the form input amount + setFieldValue('inputAmount', undefined); setFieldValue( 'selectedAsset', fungibleAssetsWithBalance[Number(e.target.value)], @@ -169,7 +170,7 @@ export function SendAssetsModal({ onChange={value => { setFieldValue('inputAmount', value); }} - currentValue={values.inputAmount} + parentFormikValue={values.inputAmount} decimalPlaces={values.selectedAsset.decimals} placeholder="0" maxValue={BigInt(values.selectedAsset.balance)} diff --git a/src/types/common.ts b/src/types/common.ts index 911e89e1fb..fd1c03888e 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -1,5 +1,8 @@ export interface BigIntValuePair { + /** A stringified, user-parseable, decimal representation of `bigintValue`. */ value: string; + + /** The actual, unformatted `bigint` value. */ bigintValue?: bigint; } From a1d5ae5b50fef19a77ea5939081a570e0381ac8f Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 2 Oct 2024 16:14:25 +0100 Subject: [PATCH 02/15] Fix delegate to self not updating input field --- src/components/ui/forms/EthAddressInput.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/ui/forms/EthAddressInput.tsx b/src/components/ui/forms/EthAddressInput.tsx index 94419998bb..0f11589f3d 100644 --- a/src/components/ui/forms/EthAddressInput.tsx +++ b/src/components/ui/forms/EthAddressInput.tsx @@ -10,6 +10,7 @@ export function AddressInput({ value, onChange, ...rest }: InputProps) { const [localValue, setLocalValue] = useState( value, ); + const debounceValue = useMemo( () => debounce((event: ChangeEvent) => { @@ -24,6 +25,10 @@ export function AddressInput({ value, onChange, ...rest }: InputProps) { }; }, [debounceValue]); + useEffect(() => { + setLocalValue(value); + }, [value]); + const handleChange = useCallback( (event: ChangeEvent) => { debounceValue(event); @@ -31,6 +36,7 @@ export function AddressInput({ value, onChange, ...rest }: InputProps) { }, [debounceValue], ); + return ( Date: Wed, 2 Oct 2024 16:16:58 +0100 Subject: [PATCH 03/15] Add code to enable easier testing of race revert conditions --- .../Roles/forms/RoleFormAssetSelector.tsx | 2 ++ .../Roles/forms/RoleFormPaymentStream.tsx | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx b/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx index 1db9f864a4..e7c254b29f 100644 --- a/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx +++ b/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx @@ -295,6 +295,8 @@ export function AssetSelector({ formIndex }: { formIndex: number }) { { setFieldValue(field.name, valuePair, true); }} diff --git a/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx b/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx index 4d55cc1dc1..355d0f35f4 100644 --- a/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx +++ b/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx @@ -1,10 +1,11 @@ import { Box, Button, Flex, FormControl, Grid, GridItem, Icon } from '@chakra-ui/react'; import { ArrowLeft, ArrowRight } from '@phosphor-icons/react'; -import { addDays } from 'date-fns'; +import { addDays, addMinutes } from 'date-fns'; import { FormikErrors, useFormikContext } from 'formik'; import { useTranslation } from 'react-i18next'; import { CARD_SHADOW } from '../../../../constants/common'; import { useRolesStore } from '../../../../store/roles'; +import { BigIntValuePair } from '../../../../types'; import { DecentDatePicker } from '../../../ui/utils/DecentDatePicker'; import { RoleFormValues, RoleHatFormValue } from '../types'; import { AssetSelector } from './RoleFormAssetSelector'; @@ -183,6 +184,29 @@ export default function RoleFormPaymentStream({ formIndex }: { formIndex: number {t('save')} + + {/* 10-MIN STREAM BUTTON */} + + + ); } From 6b0dd4e384a881fdebda24d348e6aac4e0c51eee Mon Sep 17 00:00:00 2001 From: Kellar Date: Thu, 3 Oct 2024 12:03:56 +0100 Subject: [PATCH 04/15] Put custom stream length button behind dev mode flag --- .env | 1 + .../Roles/forms/RoleFormPaymentStream.tsx | 44 ++++++++++--------- src/constants/common.ts | 11 ++++- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/.env b/.env index 853666f44c..fc69bf2bb9 100644 --- a/.env +++ b/.env @@ -57,3 +57,4 @@ VITE_APP_WALLET_CONNECT_PROJECT_ID="" # FEATURE FLAGS (Must equal "ON") VITE_APP_FLAG_STREAMS="" +VITE_APP_FLAG_DEVELOPMENT_MODE="" diff --git a/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx b/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx index 355d0f35f4..1372d6f300 100644 --- a/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx +++ b/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx @@ -3,7 +3,7 @@ import { ArrowLeft, ArrowRight } from '@phosphor-icons/react'; import { addDays, addMinutes } from 'date-fns'; import { FormikErrors, useFormikContext } from 'formik'; import { useTranslation } from 'react-i18next'; -import { CARD_SHADOW } from '../../../../constants/common'; +import { CARD_SHADOW, isDevMode } from '../../../../constants/common'; import { useRolesStore } from '../../../../store/roles'; import { BigIntValuePair } from '../../../../types'; import { DecentDatePicker } from '../../../ui/utils/DecentDatePicker'; @@ -186,27 +186,29 @@ export default function RoleFormPaymentStream({ formIndex }: { formIndex: number {/* 10-MIN STREAM BUTTON */} - - - + setFieldValue(`roleEditing.payments[${formIndex}]`, { + ...payment, + amount: { + value: '100', + bigintValue: 100000000000000000000n, + } as BigIntValuePair, + decimals: 18, + startDate: addMinutes(nowDate, 1), + endDate: addMinutes(nowDate, 10), + }); + }} + > + Ze stream ends in 10! + + + )} ); } diff --git a/src/constants/common.ts b/src/constants/common.ts index ea3952b39d..ea0d1f0e3b 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -50,7 +50,14 @@ export const SIDEBAR_WIDTH = '4.25rem'; export const MAX_CONTENT_WIDTH = '80rem'; -export const isFeatureEnabled = (feature: string) => { +const features = { + streams: 'STREAMS', + developmentMode: 'DEVELOPMENT_MODE', +} as const; + +type FeatureFlag = (typeof features)[keyof typeof features]; + +export const isFeatureEnabled = (feature: FeatureFlag) => { const featureStatus = import.meta.env[`VITE_APP_FLAG_${feature}`]; if (featureStatus === 'ON') { return true; @@ -58,3 +65,5 @@ export const isFeatureEnabled = (feature: string) => { return false; } }; + +export const isDevMode = () => isFeatureEnabled(features.developmentMode); From 9d1c154c98c199e2bb453e37e01c7a773743056b Mon Sep 17 00:00:00 2001 From: Kellar Date: Thu, 3 Oct 2024 16:20:03 +0100 Subject: [PATCH 05/15] Initial workings of the `DecentSablierStreamManagement` integration --- src/hooks/streams/useCreateSablierStream.ts | 67 +++++++++-- src/hooks/utils/useCreateRoles.ts | 113 ++++++++++-------- src/providers/NetworkConfig/networks/base.ts | 2 + .../NetworkConfig/networks/mainnet.ts | 2 + .../NetworkConfig/networks/optimism.ts | 2 + .../NetworkConfig/networks/polygon.ts | 2 + .../NetworkConfig/networks/sepolia.ts | 1 + src/types/network.ts | 1 + 8 files changed, 128 insertions(+), 62 deletions(-) diff --git a/src/hooks/streams/useCreateSablierStream.ts b/src/hooks/streams/useCreateSablierStream.ts index 7c68e20e84..6591818935 100644 --- a/src/hooks/streams/useCreateSablierStream.ts +++ b/src/hooks/streams/useCreateSablierStream.ts @@ -1,11 +1,14 @@ +import { abis } from '@fractal-framework/fractal-contracts'; import groupBy from 'lodash.groupby'; import { useCallback } from 'react'; import { Address, Hex, encodeFunctionData, erc20Abi, zeroAddress, getAddress } from 'viem'; +import GnosisSafeL2 from '../../assets/abi/GnosisSafeL2'; import SablierV2BatchAbi from '../../assets/abi/SablierV2Batch'; import { SablierV2LockupLinearAbi } from '../../assets/abi/SablierV2LockupLinear'; import { PreparedNewStreamData } from '../../components/pages/Roles/types'; import { useFractal } from '../../providers/App/AppProvider'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; +import { SENTINEL_MODULE } from '../../utils/address'; export function convertStreamIdToBigInt(streamId: string) { // streamId is formatted as ${streamContractAddress}-${chainId}-${numericId} @@ -16,7 +19,7 @@ export function convertStreamIdToBigInt(streamId: string) { export default function useCreateSablierStream() { const { - contracts: { sablierV2LockupLinear, sablierV2Batch }, + contracts: { sablierV2LockupLinear, sablierV2Batch, decentSablierMasterCopy }, } = useNetworkConfig(); const { node: { daoAddress }, @@ -76,19 +79,57 @@ export default function useCreateSablierStream() { [prepareBasicStreamData], ); - const prepareFlushStreamTx = useCallback((streamId: string, to: Address) => { - // @dev This function comes from "basic" SablierV2 - // all the types of streams are inheriting from that - // so it's safe to rely on any stream ABI + const prepareFlushStreamTxs = useCallback( + (args: { streamId: string; to: Address; smartAccount: Address }) => { + if (!daoAddress) { + throw new Error('Can not flush stream without DAO Address'); + } - const flushCalldata = encodeFunctionData({ - abi: SablierV2LockupLinearAbi, - functionName: 'withdrawMax', - args: [convertStreamIdToBigInt(streamId), to], - }); + const { streamId, to, smartAccount } = args; - return flushCalldata; - }, []); + const decentSablierManagementAddress = getAddress(decentSablierMasterCopy); + const enableModuleData = encodeFunctionData({ + abi: GnosisSafeL2, + functionName: 'enableModule', + args: [decentSablierManagementAddress], + }); + + const disableModuleData = encodeFunctionData({ + abi: GnosisSafeL2, + functionName: 'disableModule', + args: [SENTINEL_MODULE, decentSablierManagementAddress], + }); + + const withdrawMaxFromStreamData = encodeFunctionData({ + abi: `abis.DecentSablierStreamManagement`, + functionName: 'withdrawMaxFromStream', + args: [ + { + sablier: sablierV2LockupLinear, + smartAccount, + streamId, + to, + }, + ], + }); + + return [ + { + targetAddress: daoAddress, + calldata: enableModuleData, + }, + { + targetAddress: decentSablierManagementAddress, + calldata: withdrawMaxFromStreamData, + }, + { + targetAddress: daoAddress, + calldata: disableModuleData, + }, + ]; + }, + [daoAddress, decentSablierMasterCopy, sablierV2LockupLinear], + ); const prepareCancelStreamTx = useCallback((streamId: string, targetAddress: Address) => { // @dev This function comes from "basic" SablierV2 @@ -142,7 +183,7 @@ export default function useCreateSablierStream() { return { prepareBatchLinearStreamCreation, - prepareFlushStreamTx, + prepareFlushStreamTxs, prepareCancelStreamTx, prepareLinearStream, }; diff --git a/src/hooks/utils/useCreateRoles.ts b/src/hooks/utils/useCreateRoles.ts index c7aa3b8631..788f971544 100644 --- a/src/hooks/utils/useCreateRoles.ts +++ b/src/hooks/utils/useCreateRoles.ts @@ -51,7 +51,7 @@ export default function useCreateRoles() { const { t } = useTranslation(['roles', 'navigation', 'modals', 'common']); const { submitProposal } = useSubmitProposal(); - const { prepareBatchLinearStreamCreation, prepareFlushStreamTx, prepareCancelStreamTx } = + const { prepareBatchLinearStreamCreation, prepareFlushStreamTxs, prepareCancelStreamTx } = useCreateSablierStream(); const ipfsClient = useIPFSClient(); const publicClient = usePublicClient(); @@ -292,20 +292,6 @@ export default function useCreateRoles() { ], ); - const prepareHatsAccountFlushExecData = useCallback( - (streamId: string, contractAddress: Address, wearer: Address) => { - const flushStreamTxCalldata = prepareFlushStreamTx(streamId, wearer); - const wrappedFlushStreamTx = encodeFunctionData({ - abi: HatsAccount1ofNAbi, - functionName: 'execute', - args: [contractAddress, 0n, flushStreamTxCalldata, 0], - }); - - return wrappedFlushStreamTx; - }, - [prepareFlushStreamTx], - ); - const createNewHatTx = useCallback( async (formRole: RoleHatFormValueEdited, adminHatId: bigint, topHatSmartAccount: Address) => { if (formRole.name === undefined || formRole.description === undefined) { @@ -519,6 +505,8 @@ export default function useCreateRoles() { 'Cannot prepare transactions for removed role without smart account address', ); } + + // @todo: For all instances of `getAddress(formHat.wearer)` we should confirm that at this point, `formHat.wearer` is definitely an `Address` type. allTxs.push({ calldata: encodeFunctionData({ abi: HatsAbi, @@ -537,15 +525,14 @@ export default function useCreateRoles() { 'Stream ID and Stream ContractAddress is required for flush stream transaction', ); } - const wrappedFlushStreamTx = prepareHatsAccountFlushExecData( - stream.streamId, - stream.contractAddress, - getAddress(formHat.wearer), - ); - allTxs.push({ - calldata: wrappedFlushStreamTx, - targetAddress: formHat.smartAddress, + + const flushStreamTxCalldata = prepareFlushStreamTxs({ + streamId: stream.streamId, + to: getAddress(formHat.wearer), + smartAccount: formHat.smartAddress, }); + + allTxs.push(...flushStreamTxCalldata); } } @@ -603,13 +590,20 @@ export default function useCreateRoles() { if (formHat.smartAddress === undefined) { throw new Error('Cannot prepare transactions for edited role without smart address'); } + + // formHat's `wearer` is the new wearer. We grab the original wearer (before this member change attempt) + // on the hat, because we need that address to transfer to the new wearer. const originalHat = getHat(formHat.id); if (!originalHat) { throw new Error('Cannot find original hat'); } + const streamsWithFundsToClaim = getStreamsWithFundsToClaimFromFromHat(formHat); if (streamsWithFundsToClaim.length) { + // If there are unclaimed funds on any streams on the hat, we need to flush them to the original wearer. + // First, we transfer the hat to the Safe, which will then be able to withdraw the funds on behalf of the original wearer. + // Finally, we transfer the hat from the Safe to the new wearer. allTxs.push({ calldata: encodeFunctionData({ abi: HatsAbi, @@ -618,22 +612,23 @@ export default function useCreateRoles() { }), targetAddress: hatsProtocol, }); + for (const stream of streamsWithFundsToClaim) { if (!stream.streamId || !stream.contractAddress) { throw new Error( 'Stream ID and Stream ContractAddress is required for flush stream transaction', ); } - const wrappedFlushStreamTx = prepareHatsAccountFlushExecData( - stream.streamId, - stream.contractAddress, - originalHat.wearer, - ); - allTxs.push({ - calldata: wrappedFlushStreamTx, - targetAddress: formHat.smartAddress, + + const flushStreamTxCalldata = prepareFlushStreamTxs({ + streamId: stream.streamId, + to: originalHat.wearer, + smartAccount: formHat.smartAddress, }); + + allTxs.push(...flushStreamTxCalldata); } + allTxs.push({ calldata: encodeFunctionData({ abi: HatsAbi, @@ -643,7 +638,7 @@ export default function useCreateRoles() { targetAddress: hatsProtocol, }); } else { - // because the original wearer currently owns the Hat + // Since there are no streams with funds to claim, we can just transfer the hat directly to the new wearer. allTxs.push({ calldata: encodeFunctionData({ abi: HatsAbi, @@ -654,36 +649,57 @@ export default function useCreateRoles() { }); } } + if (formHat.editedRole.fieldNames.includes('payments')) { const cancelledStreamsOnHat = getCancelledStreamsFromFormHat(formHat); if (cancelledStreamsOnHat.length) { + // This role edit includes stream cancels. In case there are any unclaimed funds on these streams, + // we need to flush them out to the original wearer. + + const originalHat = getHat(formHat.id); + if (!originalHat) { + throw new Error('Cannot find original hat'); + } + for (const stream of cancelledStreamsOnHat) { if (!stream.streamId || !stream.contractAddress || !formHat.smartAddress) { throw new Error('Stream data is missing for cancel stream transaction'); } - // transfer hat to DAO + + // First transfer hat from the original wearer to the Safe allTxs.push({ calldata: encodeFunctionData({ abi: HatsAbi, functionName: 'transferHat', - args: [BigInt(formHat.id), getAddress(formHat.wearer), daoAddress], + args: [BigInt(formHat.id), originalHat.wearer, daoAddress], }), targetAddress: hatsProtocol, }); - // flush withdrawable streams + + // flush withdrawable streams to the original wearer if (stream.withdrawableAmount && stream.withdrawableAmount > 0n) { - const wrappedFlushStreamTx = prepareHatsAccountFlushExecData( - stream.streamId, - stream.contractAddress, - getAddress(formHat.wearer), - ); - allTxs.push({ - calldata: wrappedFlushStreamTx, - targetAddress: formHat.smartAddress, + const flushStreamTxCalldata = prepareFlushStreamTxs({ + streamId: stream.streamId, + to: originalHat.wearer, + smartAccount: formHat.smartAddress, }); + + allTxs.push(...flushStreamTxCalldata); } - // cancel stream + + // Cancel the stream + // @todo: Update to use DecentSablierStreamManagement instead allTxs.push(prepareCancelStreamTx(stream.streamId, stream.contractAddress)); + + // Finally, transfer the hat back to the original wearer + allTxs.push({ + calldata: encodeFunctionData({ + abi: HatsAbi, + functionName: 'transferHat', + args: [BigInt(formHat.id), daoAddress, getAddress(formHat.wearer)], + }), + targetAddress: hatsProtocol, + }); } } @@ -732,7 +748,7 @@ export default function useCreateRoles() { mintHatTx, predictSmartAccount, prepareCancelStreamTx, - prepareHatsAccountFlushExecData, + prepareFlushStreamTxs, uploadHatDescription, ], ); @@ -743,14 +759,13 @@ export default function useCreateRoles() { throw new Error('Cannot create Roles proposal without public client'); } - const { setSubmitting } = formikHelpers; - setSubmitting(true); - if (!safe) { - setSubmitting(false); throw new Error('Cannot create Roles proposal without known Safe'); } + const { setSubmitting } = formikHelpers; + setSubmitting(true); + // filter to hats that have been modified, or whose payments have been modified (ie includes `editedRole` prop) const modifiedHats: RoleHatFormValueEdited[] = values.hats .map(hat => { diff --git a/src/providers/NetworkConfig/networks/base.ts b/src/providers/NetworkConfig/networks/base.ts index 576902ee82..a77c926769 100644 --- a/src/providers/NetworkConfig/networks/base.ts +++ b/src/providers/NetworkConfig/networks/base.ts @@ -81,6 +81,8 @@ export const baseConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), + hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/mainnet.ts b/src/providers/NetworkConfig/networks/mainnet.ts index 9e7b56eeaa..bd476cb347 100644 --- a/src/providers/NetworkConfig/networks/mainnet.ts +++ b/src/providers/NetworkConfig/networks/mainnet.ts @@ -81,6 +81,8 @@ export const mainnetConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), + hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/optimism.ts b/src/providers/NetworkConfig/networks/optimism.ts index edaec30ec2..a1b3c115a8 100644 --- a/src/providers/NetworkConfig/networks/optimism.ts +++ b/src/providers/NetworkConfig/networks/optimism.ts @@ -81,6 +81,8 @@ export const optimismConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), + hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/polygon.ts b/src/providers/NetworkConfig/networks/polygon.ts index 621acd3e41..93de132510 100644 --- a/src/providers/NetworkConfig/networks/polygon.ts +++ b/src/providers/NetworkConfig/networks/polygon.ts @@ -81,6 +81,8 @@ export const polygonConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), + hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', hatsAccount1ofNMasterCopy: '0xfEf83A660b7C10a3EdaFdCF62DEee1fD8a875D29', diff --git a/src/providers/NetworkConfig/networks/sepolia.ts b/src/providers/NetworkConfig/networks/sepolia.ts index aff7723ec5..13df476eb0 100644 --- a/src/providers/NetworkConfig/networks/sepolia.ts +++ b/src/providers/NetworkConfig/networks/sepolia.ts @@ -81,6 +81,7 @@ export const sepoliaConfig: NetworkConfig = { fractalRegistry: getAddress(a.FractalRegistry), keyValuePairs: getAddress(a.KeyValuePairs), decentHatsMasterCopy: getAddress(a.DecentHats_0_1_0), + decentSablierMasterCopy: getAddress(a.DecentSablierStreamManagement), hatsProtocol: '0x3bc1A0Ad72417f2d411118085256fC53CBdDd137', erc6551Registry: '0x000000006551c19487814612e58FE06813775758', diff --git a/src/types/network.ts b/src/types/network.ts index 5c0bca9464..acd1cc7f92 100644 --- a/src/types/network.ts +++ b/src/types/network.ts @@ -53,6 +53,7 @@ export type NetworkConfig = { keyValuePairs: Address; decentHatsMasterCopy: Address; + decentSablierMasterCopy: Address; hatsProtocol: Address; erc6551Registry: Address; From cdeb78788c1982ed0ddd0b2f7528a6bbae548aab Mon Sep 17 00:00:00 2001 From: Kellar Date: Fri, 4 Oct 2024 16:38:55 +0100 Subject: [PATCH 06/15] WIP continues -- cancel streams rework + one more original hat bug fix --- src/hooks/streams/useCreateSablierStream.ts | 56 ++++++++++++++++----- src/hooks/utils/useCreateRoles.ts | 17 ++++--- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/hooks/streams/useCreateSablierStream.ts b/src/hooks/streams/useCreateSablierStream.ts index 6591818935..2302154daa 100644 --- a/src/hooks/streams/useCreateSablierStream.ts +++ b/src/hooks/streams/useCreateSablierStream.ts @@ -131,18 +131,48 @@ export default function useCreateSablierStream() { [daoAddress, decentSablierMasterCopy, sablierV2LockupLinear], ); - const prepareCancelStreamTx = useCallback((streamId: string, targetAddress: Address) => { - // @dev This function comes from "basic" SablierV2 - // all the types of streams are inheriting from that - // so it's safe to rely on any stream ABI - const cancelCallData = encodeFunctionData({ - abi: SablierV2LockupLinearAbi, - functionName: 'cancel', - args: [convertStreamIdToBigInt(streamId)], - }); - - return { calldata: cancelCallData, targetAddress }; - }, []); + const prepareCancelStreamTxs = useCallback( + (streamId: string) => { + if (!daoAddress) { + throw new Error('Can not flush stream without DAO Address'); + } + + const decentSablierManagementAddress = getAddress(decentSablierMasterCopy); + const enableModuleData = encodeFunctionData({ + abi: GnosisSafeL2, + functionName: 'enableModule', + args: [decentSablierManagementAddress], + }); + + const disableModuleData = encodeFunctionData({ + abi: GnosisSafeL2, + functionName: 'disableModule', + args: [SENTINEL_MODULE, decentSablierManagementAddress], + }); + + const cancelStreamData = encodeFunctionData({ + abi: `abis.DecentSablierStreamManagement`, + functionName: 'cancelStream', + args: [sablierV2LockupLinear, convertStreamIdToBigInt(streamId)], + }); + + return [ + { + targetAddress: daoAddress, + calldata: enableModuleData, + }, + { + targetAddress: decentSablierManagementAddress, + calldata: cancelStreamData, + }, + { + targetAddress: daoAddress, + calldata: disableModuleData, + }, + ]; + }, + [daoAddress, decentSablierMasterCopy, sablierV2LockupLinear], + ); const prepareBatchLinearStreamCreation = useCallback( (paymentStreams: PreparedNewStreamData[]) => { @@ -184,7 +214,7 @@ export default function useCreateSablierStream() { return { prepareBatchLinearStreamCreation, prepareFlushStreamTxs, - prepareCancelStreamTx, + prepareCancelStreamTxs, prepareLinearStream, }; } diff --git a/src/hooks/utils/useCreateRoles.ts b/src/hooks/utils/useCreateRoles.ts index 788f971544..6e59db5820 100644 --- a/src/hooks/utils/useCreateRoles.ts +++ b/src/hooks/utils/useCreateRoles.ts @@ -51,7 +51,7 @@ export default function useCreateRoles() { const { t } = useTranslation(['roles', 'navigation', 'modals', 'common']); const { submitProposal } = useSubmitProposal(); - const { prepareBatchLinearStreamCreation, prepareFlushStreamTxs, prepareCancelStreamTx } = + const { prepareBatchLinearStreamCreation, prepareFlushStreamTxs, prepareCancelStreamTxs } = useCreateSablierStream(); const ipfsClient = useIPFSClient(); const publicClient = usePublicClient(); @@ -507,11 +507,16 @@ export default function useCreateRoles() { } // @todo: For all instances of `getAddress(formHat.wearer)` we should confirm that at this point, `formHat.wearer` is definitely an `Address` type. + const originalHat = getHat(formHat.id); + if (!originalHat) { + throw new Error('Cannot find original hat'); + } + allTxs.push({ calldata: encodeFunctionData({ abi: HatsAbi, functionName: 'transferHat', - args: [BigInt(formHat.id), getAddress(formHat.wearer), daoAddress], + args: [BigInt(formHat.id), getAddress(originalHat.wearer), daoAddress], }), targetAddress: hatsProtocol, }); @@ -519,6 +524,7 @@ export default function useCreateRoles() { const streamsWithFundsToClaim = getStreamsWithFundsToClaimFromFormHat(formHat); if (streamsWithFundsToClaim.length) { + // This role is being removed. We need to flush out any unclaimed funds from streams on this role. for (const stream of streamsWithFundsToClaim) { if (!stream.streamId || !stream.contractAddress) { throw new Error( @@ -545,7 +551,7 @@ export default function useCreateRoles() { 'Stream ID and Stream ContractAddress is required for cancel stream transaction', ); } - allTxs.push(prepareCancelStreamTx(stream.streamId, stream.contractAddress)); + allTxs.push(...prepareCancelStreamTxs(stream.streamId)); } } @@ -688,8 +694,7 @@ export default function useCreateRoles() { } // Cancel the stream - // @todo: Update to use DecentSablierStreamManagement instead - allTxs.push(prepareCancelStreamTx(stream.streamId, stream.contractAddress)); + allTxs.push(...prepareCancelStreamTxs(stream.streamId)); // Finally, transfer the hat back to the original wearer allTxs.push({ @@ -747,7 +752,7 @@ export default function useCreateRoles() { hatsTree, mintHatTx, predictSmartAccount, - prepareCancelStreamTx, + prepareCancelStreamTxs, prepareFlushStreamTxs, uploadHatDescription, ], From df69db523d2b6ce4bf529a3bc6efc84b3576e6e5 Mon Sep 17 00:00:00 2001 From: Kellar Date: Thu, 10 Oct 2024 15:11:55 +0100 Subject: [PATCH 07/15] update to use decent stream contract --- .../pages/Roles/forms/RoleFormPaymentStream.tsx | 2 +- src/hooks/streams/useCreateSablierStream.ts | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx b/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx index cbf5f62807..a1f7009b16 100644 --- a/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx +++ b/src/components/pages/Roles/forms/RoleFormPaymentStream.tsx @@ -17,13 +17,13 @@ import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { CARD_SHADOW, isDevMode } from '../../../../constants/common'; import { useRolesStore } from '../../../../store/roles'; +import { BigIntValuePair } from '../../../../types'; import { ModalType } from '../../../ui/modals/ModalProvider'; import { useDecentModal } from '../../../ui/modals/useDecentModal'; import { DecentDatePicker } from '../../../ui/utils/DecentDatePicker'; import { RoleFormValues, RoleHatFormValue } from '../types'; import { AssetSelector } from './RoleFormAssetSelector'; import { SectionTitle } from './RoleFormSectionTitle'; -import { BigIntValuePair } from '../../../../types'; function FixedDate({ formIndex, disabled }: { formIndex: number; disabled: boolean }) { const { t } = useTranslation(['roles']); diff --git a/src/hooks/streams/useCreateSablierStream.ts b/src/hooks/streams/useCreateSablierStream.ts index 2302154daa..d02fcee6d3 100644 --- a/src/hooks/streams/useCreateSablierStream.ts +++ b/src/hooks/streams/useCreateSablierStream.ts @@ -4,7 +4,6 @@ import { useCallback } from 'react'; import { Address, Hex, encodeFunctionData, erc20Abi, zeroAddress, getAddress } from 'viem'; import GnosisSafeL2 from '../../assets/abi/GnosisSafeL2'; import SablierV2BatchAbi from '../../assets/abi/SablierV2Batch'; -import { SablierV2LockupLinearAbi } from '../../assets/abi/SablierV2LockupLinear'; import { PreparedNewStreamData } from '../../components/pages/Roles/types'; import { useFractal } from '../../providers/App/AppProvider'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; @@ -101,16 +100,9 @@ export default function useCreateSablierStream() { }); const withdrawMaxFromStreamData = encodeFunctionData({ - abi: `abis.DecentSablierStreamManagement`, + abi: abis.DecentSablierStreamManagement, functionName: 'withdrawMaxFromStream', - args: [ - { - sablier: sablierV2LockupLinear, - smartAccount, - streamId, - to, - }, - ], + args: [sablierV2LockupLinear, smartAccount, convertStreamIdToBigInt(streamId), to], }); return [ @@ -151,7 +143,7 @@ export default function useCreateSablierStream() { }); const cancelStreamData = encodeFunctionData({ - abi: `abis.DecentSablierStreamManagement`, + abi: abis.DecentSablierStreamManagement, functionName: 'cancelStream', args: [sablierV2LockupLinear, convertStreamIdToBigInt(streamId)], }); From 2086f18e1314b111711142ab33010f57b2b63e29 Mon Sep 17 00:00:00 2001 From: Kellar Date: Thu, 10 Oct 2024 15:12:02 +0100 Subject: [PATCH 08/15] bug fix --- src/hooks/DAO/loaders/governance/useERC20Claim.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/DAO/loaders/governance/useERC20Claim.ts b/src/hooks/DAO/loaders/governance/useERC20Claim.ts index 49eb0550af..2451c2ec43 100644 --- a/src/hooks/DAO/loaders/governance/useERC20Claim.ts +++ b/src/hooks/DAO/loaders/governance/useERC20Claim.ts @@ -46,11 +46,14 @@ export function useERC20Claim() { .ERC20ClaimCreated({ fromBlock: 0n }) .catch(() => []); + if (!tokenClaimArray.length) return; + const childToken = tokenClaimArray[0].args.childToken; - if (!tokenClaimArray.length || !childToken || childToken === votesTokenAddress) { + if (!childToken || childToken === votesTokenAddress) { return; } + // action to governance action.dispatch({ type: FractalGovernanceAction.SET_CLAIMING_CONTRACT, From 01f2199164e673bd9090d3646d311584f075e6c7 Mon Sep 17 00:00:00 2001 From: Kellar Date: Thu, 10 Oct 2024 18:02:21 +0100 Subject: [PATCH 09/15] Bump fractal contracts --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index b013d5feea..a45c70b7d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@fontsource/space-mono": "^5.0.19", - "@fractal-framework/fractal-contracts": "^1.2.14", + "@fractal-framework/fractal-contracts": "^1.2.15", "@graphprotocol/client-apollo": "^1.0.16", "@hatsprotocol/sdk-v1-core": "^0.9.0", "@hatsprotocol/sdk-v1-subgraph": "^1.0.0", @@ -4965,9 +4965,9 @@ "integrity": "sha512-gz9yaKtXCY+HutNvQ4APc15xwZ1f6pWXve5N55x5m/hOoGqgB9Auf3l7CitHNhNJkSKEmaM45M29b0rFeudXlg==" }, "node_modules/@fractal-framework/fractal-contracts": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@fractal-framework/fractal-contracts/-/fractal-contracts-1.2.14.tgz", - "integrity": "sha512-q3DtFx7dUmHWfFsR8eqmv9/tE1TCHcrhLLiLi7miRXpWKE2mF8ZE739UnPuRJzqBu85WiMUspmS1drcreO/Gcg==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@fractal-framework/fractal-contracts/-/fractal-contracts-1.2.15.tgz", + "integrity": "sha512-k8afRUwp/EiBNsWuUH+tjh4Ybf/LcwdD5+CX7KuCY/ejPXREUjo18b6qGSL0yfNnLJvHaIyub7g6C5oxIh6cWA==", "license": "MIT" }, "node_modules/@graphprotocol/client-add-source-name": { diff --git a/package.json b/package.json index 073be648d6..54a028b60a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@fontsource/space-mono": "^5.0.19", - "@fractal-framework/fractal-contracts": "^1.2.14", + "@fractal-framework/fractal-contracts": "^1.2.15", "@graphprotocol/client-apollo": "^1.0.16", "@hatsprotocol/sdk-v1-core": "^0.9.0", "@hatsprotocol/sdk-v1-subgraph": "^1.0.0", From 4410603f97127e6bf3d7625f3b4d63a7673776bf Mon Sep 17 00:00:00 2001 From: Kellar Date: Thu, 10 Oct 2024 18:11:23 +0100 Subject: [PATCH 10/15] Remove STREAMS feature flag. Enables payments unconditionally --- src/components/pages/Roles/RoleCard.tsx | 2 +- .../pages/Roles/RolesDetailsDrawer.tsx | 4 +-- .../pages/Roles/RolesDetailsDrawerMobile.tsx | 3 +-- src/components/pages/Roles/RolesTable.tsx | 25 +++++++------------ .../pages/Roles/forms/RoleFormTabs.tsx | 11 +++----- src/constants/common.ts | 1 - 6 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/components/pages/Roles/RoleCard.tsx b/src/components/pages/Roles/RoleCard.tsx index 2a32a1d5b6..22f16729b3 100644 --- a/src/components/pages/Roles/RoleCard.tsx +++ b/src/components/pages/Roles/RoleCard.tsx @@ -62,7 +62,7 @@ export function AvatarAndRoleName({ > {wearerAddress ? accountDisplayName : t('unassigned')} - {isFeatureEnabled('STREAMS') && paymentsCount !== undefined && ( + {paymentsCount !== undefined && ( - {isFeatureEnabled('STREAMS') && roleHat.payments && ( + {roleHat.payments && ( <> - {isFeatureEnabled('STREAMS') && roleHat.payments && ( + {roleHat.payments && ( <> {t('member')} - {isFeatureEnabled('STREAMS') && ( - - {t('activePayments')} - - )} + + {t('activePayments')} + ); @@ -194,7 +191,7 @@ export function RolesRow({ {name} - {isFeatureEnabled('STREAMS') && } + ); } @@ -226,11 +223,7 @@ export function RolesRowEdit({ editStatus={editStatus} /> - {isFeatureEnabled('STREAMS') && ( - p.isStreaming()).length || undefined} - /> - )} + p.isStreaming()).length || undefined} /> ); } diff --git a/src/components/pages/Roles/forms/RoleFormTabs.tsx b/src/components/pages/Roles/forms/RoleFormTabs.tsx index bdc550b4e5..6f79bcef46 100644 --- a/src/components/pages/Roles/forms/RoleFormTabs.tsx +++ b/src/components/pages/Roles/forms/RoleFormTabs.tsx @@ -4,7 +4,6 @@ import { useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { Hex } from 'viem'; -import { isFeatureEnabled } from '../../../../constants/common'; import { DAO_ROUTES } from '../../../../constants/routes'; import { useFractal } from '../../../../providers/App/AppProvider'; import { useNetworkConfig } from '../../../../providers/NetworkConfig/NetworkConfigProvider'; @@ -65,17 +64,15 @@ export default function RoleFormTabs({ {t('roleInfo')} - {isFeatureEnabled('STREAMS') && {t('payments')}} + {t('payments')} - {isFeatureEnabled('STREAMS') && ( - - - - )} + + + Date: Thu, 10 Oct 2024 18:12:18 +0100 Subject: [PATCH 11/15] cleanup --- src/components/pages/Roles/RoleCard.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/pages/Roles/RoleCard.tsx b/src/components/pages/Roles/RoleCard.tsx index 22f16729b3..cd4adf0b7f 100644 --- a/src/components/pages/Roles/RoleCard.tsx +++ b/src/components/pages/Roles/RoleCard.tsx @@ -3,7 +3,6 @@ import { CaretCircleRight, CaretRight } from '@phosphor-icons/react'; import { formatDuration, intervalToDuration } from 'date-fns'; import { useTranslation } from 'react-i18next'; import { getAddress, zeroAddress } from 'viem'; -import { isFeatureEnabled } from '../../../constants/common'; import { useGetDAOName } from '../../../hooks/DAO/useGetDAOName'; import useAvatar from '../../../hooks/utils/useAvatar'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; @@ -233,8 +232,7 @@ export function RoleCardEdit({ /> - {isFeatureEnabled('STREAMS') && - payments && + {payments && payments.map((payment, index) => ( Date: Fri, 11 Oct 2024 16:09:28 +0100 Subject: [PATCH 12/15] pretty --- src/components/ui/forms/BigIntInput.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ui/forms/BigIntInput.tsx b/src/components/ui/forms/BigIntInput.tsx index ed98e817e5..78089f9e3a 100644 --- a/src/components/ui/forms/BigIntInput.tsx +++ b/src/components/ui/forms/BigIntInput.tsx @@ -148,7 +148,6 @@ export function BigIntInput({ // if the parent Formik value prop changes, need to update the value useEffect(() => { - // If parentFormikValue is set to undefined, then the input should be blank if (parentFormikValue === undefined) { setInputValue(''); From 8758007179a7550654dceb12a80618e16cb1c2ac Mon Sep 17 00:00:00 2001 From: Kellar Date: Fri, 11 Oct 2024 17:37:37 +0100 Subject: [PATCH 13/15] Cleanup --- .env | 1 - src/hooks/streams/useCreateSablierStream.ts | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.env b/.env index fc69bf2bb9..c53893e9cb 100644 --- a/.env +++ b/.env @@ -56,5 +56,4 @@ VITE_APP_SITE_URL="https://app.dev.decentdao.org" VITE_APP_WALLET_CONNECT_PROJECT_ID="" # FEATURE FLAGS (Must equal "ON") -VITE_APP_FLAG_STREAMS="" VITE_APP_FLAG_DEVELOPMENT_MODE="" diff --git a/src/hooks/streams/useCreateSablierStream.ts b/src/hooks/streams/useCreateSablierStream.ts index d02fcee6d3..f4e5196ae7 100644 --- a/src/hooks/streams/useCreateSablierStream.ts +++ b/src/hooks/streams/useCreateSablierStream.ts @@ -86,17 +86,16 @@ export default function useCreateSablierStream() { const { streamId, to, smartAccount } = args; - const decentSablierManagementAddress = getAddress(decentSablierMasterCopy); const enableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'enableModule', - args: [decentSablierManagementAddress], + args: [decentSablierMasterCopy], }); const disableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'disableModule', - args: [SENTINEL_MODULE, decentSablierManagementAddress], + args: [SENTINEL_MODULE, decentSablierMasterCopy], }); const withdrawMaxFromStreamData = encodeFunctionData({ @@ -111,7 +110,7 @@ export default function useCreateSablierStream() { calldata: enableModuleData, }, { - targetAddress: decentSablierManagementAddress, + targetAddress: decentSablierMasterCopy, calldata: withdrawMaxFromStreamData, }, { @@ -129,17 +128,16 @@ export default function useCreateSablierStream() { throw new Error('Can not flush stream without DAO Address'); } - const decentSablierManagementAddress = getAddress(decentSablierMasterCopy); const enableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'enableModule', - args: [decentSablierManagementAddress], + args: [decentSablierMasterCopy], }); const disableModuleData = encodeFunctionData({ abi: GnosisSafeL2, functionName: 'disableModule', - args: [SENTINEL_MODULE, decentSablierManagementAddress], + args: [SENTINEL_MODULE, decentSablierMasterCopy], }); const cancelStreamData = encodeFunctionData({ @@ -154,7 +152,7 @@ export default function useCreateSablierStream() { calldata: enableModuleData, }, { - targetAddress: decentSablierManagementAddress, + targetAddress: decentSablierMasterCopy, calldata: cancelStreamData, }, { From e977a780b628dba50a415f50681722ac7066e49b Mon Sep 17 00:00:00 2001 From: Kellar Date: Fri, 11 Oct 2024 18:14:20 +0100 Subject: [PATCH 14/15] cleanup no-longer-relevant todo --- src/components/pages/Roles/forms/RoleFormAssetSelector.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx b/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx index 871b81ebd5..6d5663ab45 100644 --- a/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx +++ b/src/components/pages/Roles/forms/RoleFormAssetSelector.tsx @@ -304,7 +304,6 @@ export function AssetSelector({ formIndex, disabled }: { formIndex: number; disa { setFieldValue(field.name, valuePair, true); From 462eb7dd6a750569e0095b83880e5c47a5fec5b4 Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Fri, 11 Oct 2024 13:43:25 -0400 Subject: [PATCH 15/15] Bump version to 0.3.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 024276595c..7d72498b8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "decent-interface", - "version": "0.3.5", + "version": "0.3.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "decent-interface", - "version": "0.3.5", + "version": "0.3.6", "hasInstallScript": true, "dependencies": { "@amplitude/analytics-browser": "^2.11.1", diff --git a/package.json b/package.json index fb4b9ff7e0..a45dedf1ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decent-interface", - "version": "0.3.5", + "version": "0.3.6", "private": true, "dependencies": { "@amplitude/analytics-browser": "^2.11.1",