Skip to content

Commit

Permalink
Merge a80cb23 into edec103
Browse files Browse the repository at this point in the history
  • Loading branch information
0xvangrim authored Apr 20, 2022
2 parents edec103 + a80cb23 commit 12d68ee
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/assets/images/info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/images/mint.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ const Transfer: React.FC<ActionEditorProps> = ({ decodedCall, updateCall }) => {
// parse transfer state from calls
const parsedData = useMemo<TransferState>(() => {
if (!decodedCall) return null;

return {
source: decodedCall.from,
tokenAddress: decodedCall.to,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import styled from 'styled-components';
import { Input } from 'components/Guilds/common/Form/Input';
import Avatar from 'components/Guilds/Avatar';
import React, { useEffect } from 'react';
import { ActionEditorProps } from '..';
import { ethers } from 'ethers';
import useENSAvatar from 'hooks/Guilds/ether-swr/ens/useENSAvatar';
import { Box } from 'components/Guilds/common/Layout';
import { shortenAddress, MAINNET_ID } from 'utils';
import { baseInputStyles } from 'components/Guilds/common/Form/Input';
import { ReactComponent as Info } from '../../../../../assets/images/info.svg';
import StyledIcon from 'components/Guilds/common/SVG';
import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber';
import { useState } from 'react';
import NumericalInput from 'components/Guilds/common/Form/NumericalInput';
import { useTotalSupply } from 'hooks/Guilds/guild/useTotalSupply';
import { useTokenData } from 'hooks/Guilds/guild/useTokenData';

const Control = styled(Box)`
display: flex;
flex-direction: column;
margin: 0.75rem 0;
width: 100%;
`;

const ControlLabel = styled(Box)`
display: flex;
flex-direction: row;
margin-bottom: 0.75rem;
color: ${({ theme }) => theme.colors.proposalText.grey};
font-size: ${({ theme }) => theme.fontSizes.body};
font-weight: ${({ theme }) => theme.fontWeights.regular};
`;

const ControlRow = styled(Box)`
display: flex;
align-items: stretch;
height: 100%;
`;

const RepMintInput = styled(NumericalInput)`
${baseInputStyles}
display: flex;
align-items: center;
width: 100%;
&:hover,
&:focus {
border: 0.1rem solid ${({ theme }) => theme.colors.text};
}
`;

const Mint: React.FC<ActionEditorProps> = ({ decodedCall, updateCall }) => {
// parse transfer state from calls
const [repPercent, setRepPercent] = useState(0);
const [repAmount, setRepAmount] = useState(0);
const { parsedData } = useTotalSupply({ decodedCall });
const { tokenData } = useTokenData();

const totalSupply = useBigNumberToNumber(tokenData?.totalSupply, 18);

const { imageUrl } = useENSAvatar(parsedData?.toAddress, MAINNET_ID);

const setCallDataAmount = (value: string) => {
const amount = value ? ethers.utils.parseUnits(value) : null;
updateCall({
...decodedCall,
args: {
...decodedCall.args,
amount,
},
});
};

useEffect(() => {
setRepAmount((repPercent / 100) * totalSupply);
if (repAmount) {
setCallDataAmount(repAmount.toString());
}
}, [repPercent, repAmount, totalSupply]);

const handleRepChange = (e: number) => {
if (e) {
setRepPercent(e);
}
};
return (
<React.Fragment>
<Control>
<ControlLabel>
Recipient
<StyledIcon src={Info} />
</ControlLabel>
<ControlRow>
<Input
value={shortenAddress(parsedData?.toAddress)}
icon={
<Avatar
src={imageUrl}
defaultSeed={parsedData?.toAddress}
size={18}
/>
}
readOnly
/>
</ControlRow>
</Control>
<ControlRow>
<Control>
<ControlLabel>
Reputation in % <StyledIcon src={Info} />
</ControlLabel>
<ControlRow>
<RepMintInput value={repPercent} onUserInput={handleRepChange} />
</ControlRow>
</Control>
</ControlRow>
<ControlRow>
<Control>
<ControlLabel>
Reputation Amount <StyledIcon src={Info} />
</ControlLabel>
<ControlRow>
<RepMintInput
value={repAmount}
onUserInput={handleRepChange}
readOnly
/>
</ControlRow>
</Control>
</ControlRow>
</React.Fragment>
);
};

export default Mint;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Avatar from 'components/Guilds/Avatar';
import useENSAvatar from 'hooks/Guilds/ether-swr/ens/useENSAvatar';
import { FiArrowRight } from 'react-icons/fi';
import { MAINNET_ID, shortenAddress } from 'utils';
import { ActionViewProps } from '..';
import { Segment } from '../common/infoLine';
import { ReactComponent as Mint } from '../../../../../assets/images/mint.svg';
import StyledIcon from 'components/Guilds/common/SVG';
import styled from 'styled-components';
import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber';
import { useTotalSupply } from 'hooks/Guilds/guild/useTotalSupply';
import { useTokenData } from 'hooks/Guilds/guild/useTokenData';

const StyledMintIcon = styled(StyledIcon)`
margin: 0;
`;

const REPMintInfoLine: React.FC<ActionViewProps> = ({ decodedCall }) => {
const { parsedData } = useTotalSupply({ decodedCall });
const { tokenData } = useTokenData();

const totalSupply = useBigNumberToNumber(tokenData?.totalSupply, 18);

const { ensName, imageUrl } = useENSAvatar(parsedData?.toAddress, MAINNET_ID);

const roundedRepAmount = useBigNumberToNumber(parsedData?.amount, 16, 3);
const roundedRepPercent = roundedRepAmount / totalSupply;

return (
<>
<Segment>
<StyledMintIcon src={Mint} />
</Segment>
<Segment>Mint {roundedRepPercent} %</Segment>
<Segment>
<FiArrowRight />
</Segment>
<Segment>
<Avatar defaultSeed={parsedData?.toAddress} src={imageUrl} size={24} />
</Segment>
<Segment>{ensName || shortenAddress(parsedData?.toAddress)}</Segment>
</>
);
};

export default REPMintInfoLine;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Avatar from 'components/Guilds/Avatar';
import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber';
import useENSAvatar from 'hooks/Guilds/ether-swr/ens/useENSAvatar';
import { MAINNET_ID, shortenAddress } from 'utils';
import { ActionViewProps } from '..';
import { Segment } from '../common/infoLine';
import { DetailCell, DetailHeader, DetailRow } from '../common/summary';
import { useTotalSupply } from 'hooks/Guilds/guild/useTotalSupply';
import { useTokenData } from 'hooks/Guilds/guild/useTokenData';

const REPMintSummary: React.FC<ActionViewProps> = ({ decodedCall }) => {
const { parsedData } = useTotalSupply({ decodedCall });
const { tokenData } = useTokenData();
const { ensName, imageUrl } = useENSAvatar(parsedData?.toAddress, MAINNET_ID);

const roundedRepAmount = useBigNumberToNumber(parsedData?.amount, 18, 3);

return (
<>
<DetailHeader>
<DetailCell>Receiver</DetailCell>
<DetailCell>Amount</DetailCell>
</DetailHeader>

<DetailRow>
<DetailCell>
<Segment>
<Avatar
defaultSeed={parsedData?.toAddress}
src={imageUrl}
size={24}
/>
</Segment>
<Segment>{ensName || shortenAddress(parsedData?.toAddress)}</Segment>
</DetailCell>
<DetailCell>
{roundedRepAmount} {tokenData?.name}
</DetailCell>
</DetailRow>
</>
);
};

export default REPMintSummary;
27 changes: 24 additions & 3 deletions src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import { BigNumber, utils } from 'ethers';
import { DeepPartial, RequireAtLeastOne } from 'utils/types';
import { DecodedAction, DecodedCall, SupportedAction } from '../types';
import ERC20ABI from '../../../../abis/ERC20.json';
import ERC20SnapshotRep from '../../../../contracts/ERC20SnapshotRep.json';
import ERC20TransferEditor from './ERC20Transfer/ERC20TransferEditor';
import ERC20TransferInfoLine from './ERC20Transfer/ERC20TransferInfoLine';
import ERC20TransferSummary from './ERC20Transfer/ERC20TransferSummary';

import REPMintEditor from './REPMint/REPMintEditor';
import REPMintInfoLine from './REPMint/REPMintInfoLine';
import REPMintSummary from './REPMint/REPMintSummary';
export interface SupportedActionMetadata {
title: string;
}
Expand Down Expand Up @@ -37,15 +40,20 @@ export const supportedActions: Record<
summaryView: ERC20TransferSummary,
editor: ERC20TransferEditor,
},
[SupportedAction.REP_MINT]: {
title: 'Mint Reputation',
infoLineView: REPMintInfoLine,
summaryView: REPMintSummary,
editor: REPMintEditor,
},
[SupportedAction.GENERIC_CALL]: {
title: 'Generic Call',
infoLineView: () => <div>Generic Call</div>,
editor: () => <div>Generic Call Editor</div>,
},
};

const ERC20Contract = new utils.Interface(ERC20ABI);

const ERC20SnapshotRepContract = new utils.Interface(ERC20SnapshotRep.abi);
export const defaultValues: Record<
SupportedAction,
DeepPartial<DecodedAction>
Expand All @@ -62,6 +70,19 @@ export const defaultValues: Record<
},
},
},
[SupportedAction.REP_MINT]: {
contract: ERC20SnapshotRepContract,
decodedCall: {
function: ERC20SnapshotRepContract.getFunction('mint'),
to: '',
value: BigNumber.from(0),
args: {
to: '',
amount: BigNumber.from(0),
},
},
},

[SupportedAction.GENERIC_CALL]: {},
};

Expand Down
1 change: 1 addition & 0 deletions src/components/Guilds/ActionsBuilder/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { utils } from 'ethers';

export enum SupportedAction {
ERC20_TRANSFER = 'ERC20_TRANSFER',
REP_MINT = 'REP_MINT',
GENERIC_CALL = 'GENERIC_CALL',
}

Expand Down
22 changes: 20 additions & 2 deletions src/components/Guilds/ActionsModal/ContractsList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { ReactComponent as Vector } from '../../../assets/images/vector.svg';
import { ReactComponent as Mint } from '../../../assets/images/mint.svg';
import StyledIcon from '../common/SVG';
import {
RegistryContract,
Expand All @@ -15,6 +16,8 @@ import {
SectionWrapper,
Wrapper,
} from './styles';
import useGuildImplementationTypeConfig from 'hooks/Guilds/guild/useGuildImplementationType';
import { useParams } from 'react-router-dom';

interface ContractsListProps {
onSelect: (contract: RegistryContract) => void;
Expand All @@ -27,7 +30,9 @@ const ContractsList: React.FC<ContractsListProps> = ({
}) => {
const { chainId } = useWeb3React();
const { contracts } = useContractRegistry(chainId);

const { guild_id: guildAddress } =
useParams<{ chain_name?: string; guild_id?: string }>();
const { isRepGuild } = useGuildImplementationTypeConfig(guildAddress);
return (
<Wrapper>
<SectionWrapper>
Expand All @@ -42,11 +47,24 @@ const ContractsList: React.FC<ContractsListProps> = ({
Transfer & Mint
</ButtonLabel>
</ActionsButton>
{isRepGuild ? (
<ActionsButton
onClick={() => onSupportedActionSelect(SupportedAction.REP_MINT)}
>
<ButtonLabel>
<StyledIcon src={Mint} />
Mint REP
</ButtonLabel>
</ActionsButton>
) : null}
</SectionWrapper>
<SectionWrapper>
<SectionTitle>External Contracts</SectionTitle>
{contracts?.map(contract => (
<ActionsButton onClick={() => onSelect(contract)}>
<ActionsButton
key={contract.title}
onClick={() => onSelect(contract)}
>
<ButtonLabel>{contract.title}</ButtonLabel>
<ButtonDetail>
{contract.functions?.length}{' '}
Expand Down
8 changes: 7 additions & 1 deletion src/components/Guilds/ActionsModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Modal } from '../common/Modal';
import ContractActionsList from './ContractActionsList';
import ContractsList from './ContractsList';
import ParamsModal from './ParamsModal';
import { useWeb3React } from '@web3-react/core';

export const EditorWrapper = styled.div`
margin: 1.25rem;
Expand All @@ -40,7 +41,7 @@ const ActionModal: React.FC<ActionModalProps> = ({
onAddAction,
}) => {
const { guild_id: guildId } = useParams<{ guild_id?: string }>();

const { account: walletAddress } = useWeb3React();
// Supported Actions
const [selectedAction, setSelectedAction] = useState<SupportedAction>(null);
const [selectedActionContract, setSelectedActionContract] =
Expand Down Expand Up @@ -128,6 +129,11 @@ const ActionModal: React.FC<ActionModalProps> = ({

defaultDecodedAction.decodedCall.from = guildId;
defaultDecodedAction.decodedCall.callType = action;
switch (action) {
case SupportedAction.REP_MINT:
defaultDecodedAction.decodedCall.args.to = walletAddress;
break;
}
setData(defaultDecodedAction.decodedCall);
setSelectedAction(action);
setSelectedActionContract(defaultDecodedAction.contract);
Expand Down
Loading

0 comments on commit 12d68ee

Please sign in to comment.