Skip to content

Commit

Permalink
use conditional rendering for rep implementation feature (#764)
Browse files Browse the repository at this point in the history
* use conditional rendering for rep implementation features in sidebar & withdraw action

* Fix modal styles, refactor, add dev script tokens config
  • Loading branch information
MiltonTulli authored Apr 5, 2022
1 parent 4f6e7cd commit 6c326c4
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 74 deletions.
32 changes: 25 additions & 7 deletions scripts/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ async function main() {
distribution: [
{
address: '0x79706c8e413cdaee9e63f282507287b9ea9c0928',
amount: 1000,
amount: web3.utils.toWei('200'),
},
{
address: '0xc73480525e9d1198d448ece4a01daea851f72a9d',
amount: 4000,
amount: web3.utils.toWei('50'),
},
{
address: '0x3f943f38b2fbe1ee5daf0516cecfe4e0f8734351',
amount: 10000,
amount: web3.utils.toWei('10'),
},
],
},
Expand All @@ -73,15 +73,15 @@ async function main() {
distribution: [
{
address: '0x79706c8e413cdaee9e63f282507287b9ea9c0928',
amount: 1000,
amount: web3.utils.toWei('200'),
},
{
address: '0xc73480525e9d1198d448ece4a01daea851f72a9d',
amount: 4000,
amount: web3.utils.toWei('40'),
},
{
address: '0x3f943f38b2fbe1ee5daf0516cecfe4e0f8734351',
amount: 10000,
amount: web3.utils.toWei('10'),
},
],
},
Expand Down Expand Up @@ -581,14 +581,32 @@ async function main() {
logoURI:
'https://s2.coinmarketcap.com/static/img/coins/200x200/5589.png',
},
{
address: addresses.RGT,
name: 'REP Guild Token on Localhost',
decimals: 18,
symbol: 'RGT',
fetchPrice: true,
logoURI:
'https://s2.coinmarketcap.com/static/img/coins/200x200/5589.png',
},
{
address: addresses.SGT,
name: 'Snapshot Guild Token on Localhost',
decimals: 18,
symbol: 'SGT',
fetchPrice: true,
logoURI:
'https://s2.coinmarketcap.com/static/img/coins/200x200/5589.png',
},
],
guilds: [addresses.DXDGuild, addresses.REPGuild, addresses.SnapshotGuild],
};

mkdirSync(path.resolve(__dirname, '../src/configs/localhost'), {
recursive: true,
});
await writeFileSync(
writeFileSync(
path.resolve(__dirname, '../src/configs/localhost/config.json'),
JSON.stringify(developConfig, null, 2)
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/Guilds/Sidebar/MemberActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useTransactions } from '../../../contexts/Guilds';
import { useERC20Guild } from '../../../hooks/Guilds/contracts/useContract';
import useVotingPowerPercent from '../../../hooks/Guilds/guild/useVotingPowerPercent';
import useBigNumberToNumber from '../../../hooks/Guilds/conversions/useBigNumberToNumber';
import useGuildImplementationType from '../../../hooks/Guilds/guild/useGuildImplementationType';
import { Loading } from '../common/Loading';

const UserActionButton = styled(IconButton)`
Expand Down Expand Up @@ -130,6 +131,8 @@ export const MemberActions = () => {

const memberMenuRef = useRef(null);
useDetectBlur(memberMenuRef, () => setShowMenu(false));

const { isRepGuild } = useGuildImplementationType(guildAddress);
return (
<>
<DropdownMenu ref={memberMenuRef}>
Expand Down Expand Up @@ -195,7 +198,7 @@ export const MemberActions = () => {
Increase Voting Power
</LockButton>

{isUnlockable && (
{isUnlockable && !isRepGuild && (
<LockButton onClick={withdrawTokens}>Withdraw</LockButton>
)}
</MemberContainer>
Expand Down
154 changes: 95 additions & 59 deletions src/components/Guilds/StakeTokensModal/StakeTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useMemo, useState } from 'react';
import styled, { css } from 'styled-components';
import { FiArrowRight, FiInfo } from 'react-icons/fi';
import moment from 'moment';
import { useHistory, useLocation } from 'react-router';
import { useParams } from 'react-router-dom';
import { useWeb3React } from '@web3-react/core';

Expand All @@ -20,6 +21,7 @@ import NumericalInput from '../common/Form/NumericalInput';
import useVotingPowerPercent from '../../../hooks/Guilds/guild/useVotingPowerPercent';
import useStringToBigNumber from '../../../hooks/Guilds/conversions/useStringToBigNumber';
import useBigNumberToNumber from '../../../hooks/Guilds/conversions/useBigNumberToNumber';
import useGuildImplementationType from '../../../hooks/Guilds/guild/useGuildImplementationType';
import { Loading } from '../common/Loading';

const GuestContainer = styled.div`
Expand Down Expand Up @@ -51,7 +53,7 @@ const DaoTitle = styled(Heading)`
const InfoItem = styled.div`
display: flex;
font-size: ${({ theme }) => theme.fontSizes.body};
color: ${({ theme }) => theme.colors.muted};
color: ${({ theme }) => theme.colors.card.grey};
margin-bottom: 0.4rem;
`;

Expand Down Expand Up @@ -84,7 +86,7 @@ const BaseFont = css`

const InfoLabel = styled.span`
${BaseFont}
color: ${({ theme }) => theme.colors.muted};
color: ${({ theme }) => theme.colors.card.grey};
`;

const InfoValue = styled.span`
Expand All @@ -111,7 +113,7 @@ const StakeAmountInput = styled(NumericalInput)`
font-family: inherit;
`;

const ButtonLock = styled(Button)`
const ActionButton = styled(Button)`
width: 100%;
margin-top: 22px;
self-align: flex-end;
Expand Down Expand Up @@ -188,7 +190,9 @@ export const StakeTokens = () => {
stakeAmountParsed?.add(guildConfig?.totalLocked),
3
);

const history = useHistory();
const location = useLocation();
const { isRepGuild } = useGuildImplementationType(guildAddress);
return (
<GuestContainer>
<DaoBrand>
Expand All @@ -199,19 +203,51 @@ export const StakeTokens = () => {
)}
</DaoTitle>
</DaoBrand>
<InfoItem>
{guildConfig?.lockTime ? (
`${moment
.duration(guildConfig.lockTime.toNumber(), 'seconds')
.humanize()} staking period`
) : (
<Loading loading text skeletonProps={{ width: 200 }} />
)}{' '}
</InfoItem>
{!isRepGuild && (
<InfoItem>
{guildConfig?.lockTime ? (
`${moment
.duration(guildConfig.lockTime.toNumber(), 'seconds')
.humanize()} staking period`
) : (
<Loading loading text skeletonProps={{ width: 200 }} />
)}{' '}
</InfoItem>
)}

<BalanceWidget>
{!isRepGuild && (
<BalanceWidget>
<InfoRow>
<InfoLabel>Balance:</InfoLabel>
<InfoValue>
{tokenBalance && tokenInfo ? (
roundedBalance
) : (
<Loading loading text skeletonProps={{ width: 30 }} />
)}{' '}
{tokenInfo?.symbol || (
<Loading loading text skeletonProps={{ width: 10 }} />
)}
</InfoValue>
</InfoRow>
<InfoRow>
<StakeAmountInput
value={stakeAmount}
onUserInput={setStakeAmount}
/>
<Button
onClick={() =>
setStakeAmount(formatUnits(tokenBalance, tokenInfo?.decimals))
}
>
Max
</Button>
</InfoRow>
</BalanceWidget>
)}
{isRepGuild && (
<InfoRow>
<InfoLabel>Balance:</InfoLabel>
<InfoLabel>Balance</InfoLabel>
<InfoValue>
{tokenBalance && tokenInfo ? (
roundedBalance
Expand All @@ -223,17 +259,7 @@ export const StakeTokens = () => {
)}
</InfoValue>
</InfoRow>
<InfoRow>
<StakeAmountInput value={stakeAmount} onUserInput={setStakeAmount} />
<Button
onClick={() =>
setStakeAmount(formatUnits(tokenBalance, tokenInfo?.decimals))
}
>
Max
</Button>
</InfoRow>
</BalanceWidget>
)}
<InfoRow>
<InfoLabel>Your voting power</InfoLabel>
<InfoValue>
Expand All @@ -260,41 +286,51 @@ export const StakeTokens = () => {
)}
</InfoValue>
</InfoRow>
<InfoRow>
<InfoLabel>Unlock Date</InfoLabel>
<InfoValue>
{isStakeAmountValid ? (
<>
<strong>
{moment()
.add(guildConfig.lockTime.toNumber(), 'seconds')
.format('MMM Do, YYYY - h:mm a')}
</strong>{' '}
<FiInfo />
</>
) : (
'-'
)}
</InfoValue>
</InfoRow>
{stakeAmountParsed && tokenAllowance?.gte(stakeAmountParsed) ? (
<ButtonLock disabled={!isStakeAmountValid} onClick={lockTokens}>
Lock{' '}
{tokenInfo?.symbol || (
<Loading loading text skeletonProps={{ width: 10 }} />
)}
</ButtonLock>
{!isRepGuild && (
<InfoRow>
<InfoLabel>Unlock Date</InfoLabel>
<InfoValue>
{isStakeAmountValid ? (
<>
<strong>
{moment()
.add(guildConfig.lockTime.toNumber(), 'seconds')
.format('MMM Do, YYYY - h:mm a')}
</strong>{' '}
<FiInfo />
</>
) : (
'-'
)}
</InfoValue>
</InfoRow>
)}
{!isRepGuild ? (
stakeAmountParsed && tokenAllowance?.gte(stakeAmountParsed) ? (
<ActionButton disabled={!isStakeAmountValid} onClick={lockTokens}>
Lock{' '}
{tokenInfo?.symbol || (
<Loading loading text skeletonProps={{ width: 10 }} />
)}
</ActionButton>
) : (
<ActionButton
disabled={!isStakeAmountValid}
onClick={approveTokenSpending}
>
Approve{' '}
{tokenInfo?.symbol || (
<Loading loading text skeletonProps={{ width: 10 }} />
)}{' '}
Spending
</ActionButton>
)
) : (
<ButtonLock
disabled={!isStakeAmountValid}
onClick={approveTokenSpending}
<ActionButton
onClick={() => history.push(location.pathname + '/proposalType')}
>
Approve{' '}
{tokenInfo?.symbol || (
<Loading loading text skeletonProps={{ width: 10 }} />
)}{' '}
Spending
</ButtonLock>
Mint Rep
</ActionButton>
)}
</GuestContainer>
);
Expand Down
42 changes: 35 additions & 7 deletions src/hooks/Guilds/guild/useGuildImplementationType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,42 @@ import useJsonRpcProvider from '../web3/useJsonRpcProvider';
import { GuildImplementationType } from '../../../types/types.guilds.d';
import deployedHashedBytecodes from '../../../bytecodes/config.json';

const defaultImplementation = deployedHashedBytecodes.find(
({ type }) => type === GuildImplementationType.IERC20Guild
) ?? {
type: GuildImplementationType.IERC20Guild,
features: [],
bytecode_hash: '',
};

interface ImplementationTypeConfig {
type: string;
features: string[];
bytecode_hash: string;
}

interface ImplementationTypeConfigReturn extends ImplementationTypeConfig {
isRepGuild: boolean;
isSnapshotGuild: boolean;
}
const parseConfig = (
config: ImplementationTypeConfig
): ImplementationTypeConfigReturn => {
return {
...config,
isRepGuild: config.features.includes('REP'),
isSnapshotGuild: config.features.includes('SNAPSHOT'),
};
};

/**
* @function useGuildImplementationType
* @param {string} guildAddress
* @returns {string} GuildImplementationType. 'SnapshotRepERC20Guild' | 'DXDGuild' | 'ERC20Guild' | 'IERC20Guild'
*/
export default function useGuildImplementationType(
export default function useGuildImplementationTypeConfig(
guildAddress: string
): GuildImplementationType {
): ImplementationTypeConfigReturn {
const [guildBytecode, setGuildBytecode] = useState<string>('');
const provider = useJsonRpcProvider();

Expand All @@ -23,15 +51,15 @@ export default function useGuildImplementationType(
getBytecode();
}, [guildAddress, provider]);

const implementationType: GuildImplementationType = useMemo(() => {
if (!guildBytecode) return GuildImplementationType.IERC20Guild;
const implementationTypeConfig: ImplementationTypeConfig = useMemo(() => {
if (!guildBytecode) return defaultImplementation;

const match = deployedHashedBytecodes.find(
({ bytecode_hash }) => guildBytecode === bytecode_hash
);

return match ? match.type : GuildImplementationType.IERC20Guild; // default to IERC20Guild
}, [guildBytecode]) as GuildImplementationType;
return match ? match : defaultImplementation; // default to IERC20Guild
}, [guildBytecode]);

return implementationType;
return parseConfig(implementationTypeConfig);
}

0 comments on commit 6c326c4

Please sign in to comment.