Skip to content

Commit

Permalink
Merge pull request #4889 from Giveth/base-anchor-contract
Browse files Browse the repository at this point in the history
Recurring donations setup on Base
  • Loading branch information
kkatusic authored Dec 12, 2024
2 parents e720e3a + c0ee3d9 commit 7bea3e4
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 16 deletions.
4 changes: 4 additions & 0 deletions src/apollo/gql/gqlProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const PROJECT_CARD_FIELDS = gql`
anchorContracts {
address
isActive
networkId
}
}
`;
Expand Down Expand Up @@ -196,6 +197,7 @@ export const FETCH_PROJECT_BY_SLUG_DONATION = gql`
anchorContracts {
address
isActive
networkId
}
}
}
Expand Down Expand Up @@ -294,6 +296,7 @@ export const FETCH_PROJECT_BY_SLUG_SINGLE_PROJECT = gql`
anchorContracts {
address
isActive
networkId
}
}
}
Expand Down Expand Up @@ -332,6 +335,7 @@ export const FETCH_PROJECT_BY_ID = gql`
anchorContracts {
address
isActive
networkId
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/apollo/gql/gqlSuperfluid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ export const CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY = gql`
$projectId: Int!
$networkId: Int!
$address: String!
$recipientAddress: String
$txHash: String!
) {
addAnchorContractAddress(
projectId: $projectId
networkId: $networkId
address: $address
recipientAddress: $recipientAddress
txHash: $txHash
) {
id
Expand Down
1 change: 1 addition & 0 deletions src/apollo/gql/gqlUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export const FETCH_USER_RECURRING_DONATIONS = gql`
anchorContracts {
address
isActive
networkId
}
}
finished
Expand Down
1 change: 1 addition & 0 deletions src/apollo/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface IEstimatedMatching {
export interface IAnchorContractData {
address: Address;
isActive: boolean;
networkId: number;
}

export interface IProject {
Expand Down
90 changes: 81 additions & 9 deletions src/components/views/create/AddressInterface.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { useIntl } from 'react-intl';
import { useAccount, useSwitchChain } from 'wagmi';
import styled, { css } from 'styled-components';
import {
B,
Expand All @@ -23,13 +25,16 @@ import { getChainName } from '@/lib/network';
import { IChainType } from '@/types/config';
import { findAddressByChain } from '@/lib/helpers';
import { useGeneralWallet } from '@/providers/generalWalletProvider';
import { IAnchorContractData } from '@/apollo/types/types';
import { IAnchorContractData, IProject } from '@/apollo/types/types';
import { IconWithTooltip } from '@/components/IconWithToolTip';
import { EInputs } from './types';
import links from '@/lib/constants/links';
import { STOP_RECURRING_SETUP_ON_CREATION } from './CreateProject';
import { saveAnchorContract } from './AlloProtocol/AlloProtocolModal';

interface IAddressInterfaceProps extends IChainType {
networkId: number;
project?: IProject;
onButtonClick?: () => void;
anchorContractData?: IAnchorContractData;
isEditMode?: boolean;
Expand All @@ -41,32 +46,54 @@ interface IconContainerProps {

const AddressInterface = ({
networkId,
project,
onButtonClick,
chainType,
anchorContractData,
isEditMode,
}: IAddressInterfaceProps) => {
const { chain } = useAccount();
const { switchChain } = useSwitchChain();
const { setValue, watch } = useFormContext();
const { formatMessage } = useIntl();
const { isOnEVM } = useGeneralWallet();

const [hasAnchorContract, setHasAnchorContract] = useState(
anchorContractData?.isActive || false,
);

const isOnOptimism = chain
? chain.id === config.OPTIMISM_NETWORK_NUMBER
: false;
const isOnBase = chain ? chain.id === config.BASE_NETWORK_NUMBER : false;

const inputName = EInputs.addresses;
const alloProtocolRegistry = watch(EInputs.alloProtocolRegistry) as boolean;

const value = watch(inputName);

const isOptimism = networkId === config.OPTIMISM_NETWORK_NUMBER;
const isBase = networkId === config.BASE_NETWORK_NUMBER;

const addressObj = findAddressByChain(value, networkId, chainType);
const walletAddress = addressObj?.address;

const hasAddress = !!walletAddress;
const hasAnchorContract = !!anchorContractData?.isActive;

const hasOptimismAddress = !!findAddressByChain(
value,
config.OPTIMISM_NETWORK_NUMBER,
chainType,
);
const hasBaseAddress = !!findAddressByChain(
value,
config.BASE_NETWORK_NUMBER,
chainType,
);
const isRecurringOnOptimismReady = isOptimism && hasOptimismAddress;
const isRecurringOnBaseReady = isBase && hasBaseAddress;
const isRecurringDonationsReady =
isRecurringOnBaseReady || isRecurringOnOptimismReady;

return (
<Container>
Expand Down Expand Up @@ -117,7 +144,7 @@ const AddressInterface = ({
{hasAddress ? walletAddress : 'No address added yet!'}
</AddressContainer>
{hasAddress &&
(hasAnchorContract && isOptimism ? (
(hasAnchorContract && (isOptimism || isBase) ? (
<IconWithTooltip
direction='top'
icon={
Expand Down Expand Up @@ -153,10 +180,10 @@ const AddressInterface = ({
</IconContainer>
))}
</Flex>
{isOptimism && isOnEVM && (
// Render this section only on Optimism
{(isOptimism || isBase) && isOnEVM && (
// Render this section only on Optimism and Base
<AlloProtocolContainer>
<Flex>
<Flex $flexDirection='column' $alignItems='end'>
<div>
<B>
{hasAnchorContract && isEditMode
Expand Down Expand Up @@ -192,18 +219,58 @@ const AddressInterface = ({
<IconCheckContainer>
<IconCheck16 color={brandColors.giv[100]} />
</IconCheckContainer>
) : STOP_RECURRING_SETUP_ON_CREATION ? (
<EnableBtn>
<Button
buttonType={
isRecurringDonationsReady
? 'secondary'
: 'texty-secondary'
}
label={'Enable'}
disabled={!isRecurringDonationsReady}
onClick={async () => {
if (!project) return;
if (
isRecurringOnOptimismReady &&
!isOnOptimism
) {
switchChain?.({
chainId:
config.OPTIMISM_NETWORK_NUMBER,
});
} else if (
isRecurringOnBaseReady &&
!isOnBase
) {
switchChain?.({
chainId:
config.BASE_NETWORK_NUMBER,
});
}

await saveAnchorContract({
addedProjectState: project,
chainId: networkId,
recipientAddress:
walletAddress || value,
});
setHasAnchorContract(true);
}}
/>
</EnableBtn>
) : (
<ToggleSwitch
isOn={alloProtocolRegistry}
toggleOnOff={() => {
if (!hasOptimismAddress) return;
if (!isRecurringDonationsReady) return;
setValue(
EInputs.alloProtocolRegistry,
!alloProtocolRegistry,
);
}}
label=''
disabled={!hasOptimismAddress}
disabled={!isRecurringDonationsReady}
/>
)}
</Flex>
Expand Down Expand Up @@ -233,7 +300,7 @@ const TopContainer = styled.div`
`;

const MiddleContainer = styled.div`
padding: 24px 0;
padding: 24px 0 0 0;
`;

const AddressContainer = styled.div<{ $hasAddress: boolean }>`
Expand Down Expand Up @@ -286,4 +353,9 @@ const CustomLink = styled.a`
cursor: pointer;
`;

const EnableBtn = styled.div`
width: 100px;
margin: 12px 0 0 0;
`;

export default AddressInterface;
56 changes: 56 additions & 0 deletions src/components/views/create/AlloProtocol/AlloProtocolModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,62 @@ interface IAlloProtocolModal extends IModal {
addedProjectState: IProject;
}

export const saveAnchorContract = async ({
addedProjectState,
chainId,
recipientAddress,
}: {
addedProjectState: IProject;
chainId: number;
recipientAddress?: string;
}) => {
try {
const isOptimism = chainId === config.OPTIMISM_NETWORK_NUMBER;
const hash = await writeContract(wagmiConfig, {
address: isOptimism
? config.OPTIMISM_CONFIG.anchorRegistryAddress
: config.BASE_CONFIG.anchorRegistryAddress,
functionName: 'createProfile',
abi: createProfileABI.abi,
chainId,
args: [
generateRandomNonce(), //nonce
addedProjectState?.id!,
{
protocol: 1,
pointer: '',
},
addedProjectState?.adminUser?.walletAddress, //admin user wallet address
[],
],
});
if (hash) {
const data = await waitForTransactionReceipt(wagmiConfig, {
hash: hash,
chainId,
});

const contractAddress = extractContractAddressFromString(
data.logs[0].data,
);

//Call backend to update project
await client.mutate({
mutation: CREATE_ANCHOR_CONTRACT_ADDRESS_QUERY,
variables: {
projectId: Number(addedProjectState.id),
networkId: chainId,
address: contractAddress,
recipientAddress,
txHash: hash,
},
});
}
} catch (error) {
console.error('Error Contract', error);
}
};

const AlloProtocolModal: FC<IAlloProtocolModal> = ({
setShowModal,
addedProjectState,
Expand Down
22 changes: 16 additions & 6 deletions src/components/views/create/CreateProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '@/apollo/gql/gqlProjects';
import {
EProjectSocialMediaType,
IAnchorContractData,
IProject,
IProjectCreation,
IProjectEdition,
Expand Down Expand Up @@ -59,6 +60,7 @@ import SocialMedias from './SocialMediaBox/SocialMedias';
import { CreateHeader } from './CreateHeader';

const ALL_CHAINS = config.CHAINS;
export const STOP_RECURRING_SETUP_ON_CREATION = true;

interface ICreateProjectProps {
project?: IProjectEdition;
Expand Down Expand Up @@ -405,7 +407,12 @@ const CreateProject: FC<ICreateProjectProps> = ({ project }) => {
if (addedProject) {
// Success

if (watchAlloProtocolRegistry && hasOptimismAddress && !draft) {
if (
!STOP_RECURRING_SETUP_ON_CREATION &&
watchAlloProtocolRegistry &&
hasOptimismAddress &&
!draft
) {
setShowAlloProtocolModal(true);
localStorage.removeItem(StorageLabel.CREATE_PROJECT_FORM);
} else {
Expand Down Expand Up @@ -449,7 +456,6 @@ const CreateProject: FC<ICreateProjectProps> = ({ project }) => {
localStorage.removeItem(StorageLabel.CREATE_PROJECT_FORM);
}
};

return (
<>
<CreateHeader
Expand Down Expand Up @@ -530,6 +536,7 @@ const CreateProject: FC<ICreateProjectProps> = ({ project }) => {
{ALL_CHAINS.map(chain => (
<AddressInterface
key={chain.id}
project={project as IProject}
networkId={chain.id}
chainType={
(chain as NonEVMChain).chainType
Expand All @@ -545,10 +552,13 @@ const CreateProject: FC<ICreateProjectProps> = ({ project }) => {
}}
isEditMode={isEditMode}
anchorContractData={
(project?.anchorContracts &&
project
?.anchorContracts[0]) ??
undefined
project?.anchorContracts?.find(
(
contract: IAnchorContractData,
) =>
contract.networkId ===
chain.id,
) ?? undefined
}
/>
))}
Expand Down
1 change: 1 addition & 0 deletions src/config/development.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ const config: EnvConfig = {
gasPreference: {
// Keep it empty for automatic configuration
},
anchorRegistryAddress: '0x4AAcca72145e1dF2aeC137E1f3C5E3D75DB8b5f3',
chainLogo: (logoSize?: number) => <IconBase size={logoSize} />,
},

Expand Down
1 change: 1 addition & 0 deletions src/config/production.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ const config: EnvConfig = {
gasPreference: {
// Keep it empty for automatic configuration
},
anchorRegistryAddress: '0x4AAcca72145e1dF2aeC137E1f3C5E3D75DB8b5f3',
subgraphAddress: '',
coingeckoChainName: 'base',
chainLogo: (logoSize = 24) => <IconBase size={logoSize} />,
Expand Down
Loading

0 comments on commit 7bea3e4

Please sign in to comment.