@smartinvoicexyz/hooks
Version:
Unified source for React hooks used across the Smart Invoice protocol.
120 lines (119 loc) • 4.71 kB
JavaScript
import { ESCROW_ZAP_ABI } from '@smartinvoicexyz/constants';
import { logDebug } from '@smartinvoicexyz/utils';
import _ from 'lodash';
import { useCallback, useMemo } from 'react';
import { encodeAbiParameters, isAddress, parseUnits } from 'viem';
import { useChainId, useSimulateContract, useWriteContract } from 'wagmi';
const separateOwnersAndAllocations = (ownersAndAllocations) => {
const sortedOwnersAndAllocations = _.sortBy(ownersAndAllocations, 'address');
return {
owners: _.map(sortedOwnersAndAllocations, 'address'),
percentAllocations: _.map(sortedOwnersAndAllocations, (o) => _.toNumber(o.percent) * 1e4),
};
};
export const useEscrowZap = ({ ownersAndAllocations, provider, milestones, client, threshold, arbitration = 0, projectTeamSplit = false, daoSplit = false, safetyValveDate, details, enabled = true, networkConfig, onSuccess, }) => {
const chainId = useChainId();
const { owners, percentAllocations } = separateOwnersAndAllocations(ownersAndAllocations);
const saltNonce = Math.floor(new Date().getTime() / 1000);
const milestoneAmounts = _.map(milestones, (a) => a.value && parseUnits(a.value, networkConfig.tokenDecimals));
const { tokenAddress } = networkConfig;
const resolver = daoSplit ? networkConfig.resolver : networkConfig.daoAddress;
const encodedSafeData = useMemo(() => {
if (!threshold || !saltNonce)
return encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [BigInt(0), BigInt(0)]);
return encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [BigInt(threshold), BigInt(saltNonce)]);
}, [threshold, saltNonce]);
logDebug('encodeSafeData - ', {
threshold,
saltNonce,
compiledData: !!encodedSafeData,
});
const encodedSplitData = useMemo(() => encodeAbiParameters([{ type: 'bool' }, { type: 'bool' }], [projectTeamSplit, daoSplit]), [projectTeamSplit, daoSplit]);
logDebug('encodeSplitData - ', {
projectTeamSplit,
daoSplit,
compiledData: !!encodedSplitData,
});
const encodedEscrowData = useMemo(() => {
if (!isAddress(client) ||
!(arbitration === 0 || arbitration === 1) ||
!details ||
!isAddress(resolver) ||
!isAddress(tokenAddress) ||
!safetyValveDate)
return undefined;
return encodeAbiParameters([
{ type: 'address' },
{ type: 'uint32' },
{ type: 'address' },
{ type: 'address' },
{ type: 'uint256' },
{ type: 'uint256' },
{ type: 'bytes32' },
], [
client,
arbitration,
resolver,
tokenAddress,
BigInt(Math.floor(_.toNumber(safetyValveDate) / 1000)),
BigInt(saltNonce),
details,
]);
}, [tokenAddress, safetyValveDate, details, client, arbitration, resolver]);
logDebug('encodeEscrowData - ', {
client,
arbitration,
resolver,
tokenAddress,
safetyValveDate,
saltNonce,
details,
milestoneAmounts,
compiledData: !!encodedEscrowData,
});
const { data, isLoading: prepareLoading, error: prepareError, status, } = useSimulateContract({
chainId,
address: networkConfig.zapAddress,
abi: ESCROW_ZAP_ABI,
functionName: 'createSafeSplitEscrow',
args: [
owners,
percentAllocations,
milestoneAmounts,
encodedSafeData,
provider, // _safeAddress
encodedSplitData,
encodedEscrowData,
],
query: {
enabled: _.isEqual(_.size(percentAllocations), _.size(owners)) &&
!_.isEmpty(milestoneAmounts) &&
!!encodedSafeData &&
!!provider && // _safeAddress
!!encodedSplitData &&
!!encodedEscrowData &&
enabled,
},
});
logDebug('prepareError', prepareError, status);
const { writeContractAsync, isPending: writeLoading, error: writeError, } = useWriteContract({
mutation: {
onSuccess: async (hash) => {
onSuccess?.(hash);
},
},
});
const writeAsync = useCallback(async () => {
if (!data) {
logDebug('writeAsync - no data');
return undefined;
}
return writeContractAsync(data.request);
}, [writeContractAsync, data]);
return {
writeAsync,
isLoading: prepareLoading || writeLoading || !details,
prepareError,
writeError,
};
};