Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2534315f1a |
@@ -71,27 +71,18 @@ const CreateTeamFormContainer = ({ isSolo }: { isSolo: boolean }) => {
|
||||
|
||||
if (status === 'confirmed') {
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col items-start gap-2"
|
||||
data-testid="team-creation-success-message"
|
||||
>
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
<p className="text-sm">{t('Team creation transaction successful')}</p>
|
||||
{code && (
|
||||
<>
|
||||
<p className="text-sm">
|
||||
Your team ID is:{' '}
|
||||
<span
|
||||
className="font-mono break-all"
|
||||
data-testid="team-id-display"
|
||||
>
|
||||
{code}
|
||||
</span>
|
||||
<span className="font-mono break-all">{code}</span>
|
||||
</p>
|
||||
<TradingAnchorButton
|
||||
href={Links.COMPETITIONS_TEAM(code)}
|
||||
intent={Intent.Info}
|
||||
size="small"
|
||||
data-testid="view-team-button"
|
||||
>
|
||||
{t('View team')}
|
||||
</TradingAnchorButton>
|
||||
|
||||
@@ -16,8 +16,6 @@ import { CompetitionsLeaderboard } from '../../components/competitions/competiti
|
||||
import { useTeams } from '../../lib/hooks/use-teams';
|
||||
import take from 'lodash/take';
|
||||
import { usePageTitle } from '../../lib/hooks/use-page-title';
|
||||
import { TeamCard } from '../../components/competitions/team-card';
|
||||
import { useMyTeam } from '../../lib/hooks/use-my-team';
|
||||
|
||||
export const CompetitionsHome = () => {
|
||||
const t = useT();
|
||||
@@ -35,13 +33,6 @@ export const CompetitionsHome = () => {
|
||||
|
||||
const { data: teamsData, loading: teamsLoading } = useTeams();
|
||||
|
||||
const {
|
||||
team: myTeam,
|
||||
stats: myTeamStats,
|
||||
games: myTeamGames,
|
||||
rank: myTeamRank,
|
||||
} = useMyTeam();
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<CompetitionsHeader title={t('Competitions')}>
|
||||
@@ -52,83 +43,65 @@ export const CompetitionsHome = () => {
|
||||
</p>
|
||||
</CompetitionsHeader>
|
||||
|
||||
{/** Team card */}
|
||||
{myTeam ? (
|
||||
<>
|
||||
<h2 className="text-2xl mb-6">{t('My team')}</h2>
|
||||
<div className="mb-12">
|
||||
<TeamCard
|
||||
team={myTeam}
|
||||
rank={myTeamRank}
|
||||
stats={myTeamStats}
|
||||
games={myTeamGames}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/** Get started */}
|
||||
<h2 className="text-2xl mb-6">{t('Get started')}</h2>
|
||||
{/** Get started */}
|
||||
<h2 className="text-2xl mb-6">{t('Get started')}</h2>
|
||||
|
||||
<CompetitionsActionsContainer>
|
||||
<CompetitionsAction
|
||||
variant="A"
|
||||
title={t('Create a team')}
|
||||
description={t(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit placeat ipsum minus nemo error dicta.'
|
||||
)}
|
||||
actionElement={
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(Links.COMPETITIONS_CREATE_TEAM());
|
||||
}}
|
||||
data-testId="create-public-team-button"
|
||||
>
|
||||
{t('Create a public team')}
|
||||
</TradingButton>
|
||||
}
|
||||
/>
|
||||
<CompetitionsAction
|
||||
variant="B"
|
||||
title={t('Solo team / lone wolf')}
|
||||
description={t(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit placeat ipsum minus nemo error dicta.'
|
||||
)}
|
||||
actionElement={
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(Links.COMPETITIONS_CREATE_TEAM_SOLO());
|
||||
}}
|
||||
>
|
||||
{t('Create a private team')}
|
||||
</TradingButton>
|
||||
}
|
||||
/>
|
||||
<CompetitionsAction
|
||||
variant="C"
|
||||
title={t('Join a team')}
|
||||
description={t(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit placeat ipsum minus nemo error dicta.'
|
||||
)}
|
||||
actionElement={
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(Links.COMPETITIONS_TEAMS());
|
||||
}}
|
||||
>
|
||||
{t('Choose a team')}
|
||||
</TradingButton>
|
||||
}
|
||||
/>
|
||||
</CompetitionsActionsContainer>
|
||||
</>
|
||||
)}
|
||||
<CompetitionsActionsContainer>
|
||||
<CompetitionsAction
|
||||
variant="A"
|
||||
title={t('Create a team')}
|
||||
description={t(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit placeat ipsum minus nemo error dicta.'
|
||||
)}
|
||||
actionElement={
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(Links.COMPETITIONS_CREATE_TEAM());
|
||||
}}
|
||||
>
|
||||
{t('Create a public team')}
|
||||
</TradingButton>
|
||||
}
|
||||
/>
|
||||
<CompetitionsAction
|
||||
variant="B"
|
||||
title={t('Solo team / lone wolf')}
|
||||
description={t(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit placeat ipsum minus nemo error dicta.'
|
||||
)}
|
||||
actionElement={
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(Links.COMPETITIONS_CREATE_TEAM_SOLO());
|
||||
}}
|
||||
>
|
||||
{t('Create a private team')}
|
||||
</TradingButton>
|
||||
}
|
||||
/>
|
||||
<CompetitionsAction
|
||||
variant="C"
|
||||
title={t('Join a team')}
|
||||
description={t(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit placeat ipsum minus nemo error dicta.'
|
||||
)}
|
||||
actionElement={
|
||||
<TradingButton
|
||||
intent={Intent.Primary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(Links.COMPETITIONS_TEAMS());
|
||||
}}
|
||||
>
|
||||
{t('Choose a team')}
|
||||
</TradingButton>
|
||||
}
|
||||
/>
|
||||
</CompetitionsActionsContainer>
|
||||
|
||||
{/** List of available games */}
|
||||
<h2 className="text-2xl mb-6">{t('Games')}</h2>
|
||||
|
||||
@@ -105,11 +105,7 @@ export const JoinButton = ({
|
||||
// Party is in a team, but not this one
|
||||
else if (partyTeam && partyTeam.teamId !== team.teamId) {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => onJoin('switch')}
|
||||
intent={Intent.Primary}
|
||||
data-testid="switch-team-button"
|
||||
>
|
||||
<Button onClick={() => onJoin('switch')} intent={Intent.Primary}>
|
||||
{t('Switch team')}{' '}
|
||||
</Button>
|
||||
);
|
||||
@@ -219,11 +215,7 @@ const DialogContent = ({
|
||||
</>
|
||||
)}
|
||||
<div className="flex justify-between gap-2">
|
||||
<Button
|
||||
onClick={joinTeam}
|
||||
intent={Intent.Success}
|
||||
data-testid="confirm-switch-button"
|
||||
>
|
||||
<Button onClick={joinTeam} intent={Intent.Success}>
|
||||
{t('Confirm')}
|
||||
</Button>
|
||||
<Button onClick={onCancel} intent={Intent.Danger}>
|
||||
|
||||
@@ -115,12 +115,9 @@ export const TeamForm = ({
|
||||
<form onSubmit={handleSubmit(sendTransaction)}>
|
||||
<input type="hidden" {...register('id')} />
|
||||
<TradingFormGroup label={t('Team name')} labelFor="name">
|
||||
<TradingInput
|
||||
{...register('name', { required: t('Required') })}
|
||||
data-testid="team-name-input"
|
||||
/>
|
||||
<TradingInput {...register('name', { required: t('Required') })} />
|
||||
{errors.name?.message && (
|
||||
<TradingInputError forInput="name" data-testid="team-name-error">
|
||||
<TradingInputError forInput="name">
|
||||
{errors.name.message}
|
||||
</TradingInputError>
|
||||
)}
|
||||
@@ -136,10 +133,9 @@ export const TeamForm = ({
|
||||
{...register('url', {
|
||||
pattern: { value: URL_REGEX, message: t('Invalid URL') },
|
||||
})}
|
||||
data-testid="team-url-input"
|
||||
/>
|
||||
{errors.url?.message && (
|
||||
<TradingInputError forInput="url" data-testid="team-url-error">
|
||||
<TradingInputError forInput="url">
|
||||
{errors.url.message}
|
||||
</TradingInputError>
|
||||
)}
|
||||
@@ -156,13 +152,9 @@ export const TeamForm = ({
|
||||
message: t('Invalid image URL'),
|
||||
},
|
||||
})}
|
||||
data-testid="avatar-url-input"
|
||||
/>
|
||||
{errors.avatarUrl?.message && (
|
||||
<TradingInputError
|
||||
forInput="avatarUrl"
|
||||
data-testid="avatar-url-error"
|
||||
>
|
||||
<TradingInputError forInput="avatarUrl">
|
||||
{errors.avatarUrl.message}
|
||||
</TradingInputError>
|
||||
)}
|
||||
@@ -187,7 +179,6 @@ export const TeamForm = ({
|
||||
onCheckedChange={(value) => {
|
||||
field.onChange(value);
|
||||
}}
|
||||
data-testid="team-private-checkbox"
|
||||
/>
|
||||
);
|
||||
}}
|
||||
@@ -216,13 +207,9 @@ export const TeamForm = ({
|
||||
},
|
||||
},
|
||||
})}
|
||||
data-testid="team-allow-list-textarea"
|
||||
/>
|
||||
{errors.allowList?.message && (
|
||||
<TradingInputError
|
||||
forInput="avatarUrl"
|
||||
data-testid="team-allow-list-error"
|
||||
>
|
||||
<TradingInputError forInput="avatarUrl">
|
||||
{errors.allowList.message}
|
||||
</TradingInputError>
|
||||
)}
|
||||
@@ -297,12 +284,7 @@ const SubmitButton = ({
|
||||
|
||||
return (
|
||||
<div className="flex gap-2 items-baseline">
|
||||
<TradingButton
|
||||
type="submit"
|
||||
intent={Intent.Info}
|
||||
disabled={disabled}
|
||||
data-testid="team-form-submit-button"
|
||||
>
|
||||
<TradingButton type="submit" intent={Intent.Info} disabled={disabled}>
|
||||
{text}
|
||||
</TradingButton>
|
||||
{status === 'confirmed' && confirmed}
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
import { type Team } from '../../lib/hooks/use-team';
|
||||
import { type ComponentProps } from 'react';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { type Team } from '../../lib/hooks/use-team';
|
||||
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { Links } from '../../lib/links';
|
||||
import { useT } from '../../lib/use-t';
|
||||
|
||||
export const UpdateTeamButton = ({
|
||||
team,
|
||||
size = 'medium',
|
||||
}: {
|
||||
team: Pick<Team, 'teamId' | 'referrer'>;
|
||||
size?: ComponentProps<typeof TradingAnchorButton>['size'];
|
||||
}) => {
|
||||
export const UpdateTeamButton = ({ team }: { team: Team }) => {
|
||||
const t = useT();
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
|
||||
if (pubKey && !isReadOnly && pubKey === team.referrer) {
|
||||
return (
|
||||
<TradingAnchorButton
|
||||
size={size}
|
||||
data-testid="update-team-button"
|
||||
href={Links.COMPETITIONS_UPDATE_TEAM(team.teamId)}
|
||||
intent={Intent.Info}
|
||||
|
||||
@@ -5,11 +5,7 @@ export const BORDER_COLOR = 'border-vega-clight-500 dark:border-vega-cdark-500';
|
||||
export const GRADIENT =
|
||||
'bg-gradient-to-b from-vega-clight-800 dark:from-vega-cdark-800 to-transparent';
|
||||
|
||||
export const Box = ({
|
||||
children,
|
||||
backgroundImage,
|
||||
...props
|
||||
}: HTMLAttributes<HTMLDivElement> & { backgroundImage?: string }) => {
|
||||
export const Box = (props: HTMLAttributes<HTMLDivElement>) => {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
@@ -17,22 +13,9 @@ export const Box = ({
|
||||
BORDER_COLOR,
|
||||
GRADIENT,
|
||||
'border rounded-lg',
|
||||
'relative p-6 overflow-hidden',
|
||||
'p-6',
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{Boolean(backgroundImage?.length) && (
|
||||
<div
|
||||
className={classNames(
|
||||
'pointer-events-none',
|
||||
'bg-no-repeat bg-center bg-[length:500px_500px]',
|
||||
'absolute top-0 left-0 w-full h-full -z-10 opacity-30 blur-lg'
|
||||
)}
|
||||
style={{ backgroundImage: `url("${backgroundImage}")` }}
|
||||
></div>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import classNames from 'classnames';
|
||||
const NUM_AVATARS = 20;
|
||||
const AVATAR_PATHNAME_PATTERN = '/team-avatars/{id}.png';
|
||||
|
||||
export const getFallbackAvatar = (teamId: string) => {
|
||||
const getFallbackAvatar = (teamId: string) => {
|
||||
const avatarId = ((parseInt(teamId, 16) % NUM_AVATARS) + 1)
|
||||
.toString()
|
||||
.padStart(2, '0'); // between 01 - 20
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
import { type TeamGame, type TeamStats } from '../../lib/hooks/use-team';
|
||||
import { type TeamsFieldsFragment } from '../../lib/hooks/__generated__/Teams';
|
||||
import { TeamAvatar, getFallbackAvatar } from './team-avatar';
|
||||
import { FavoriteGame, Stat } from './team-stats';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { formatNumberRounded } from '@vegaprotocol/utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { Box } from './box';
|
||||
import { Intent, Tooltip, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||
import { Links } from '../../lib/links';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { take } from 'lodash';
|
||||
import { DispatchMetricLabels } from '@vegaprotocol/types';
|
||||
import classNames from 'classnames';
|
||||
import { UpdateTeamButton } from '../../client-pages/competitions/update-team-button';
|
||||
|
||||
export const TeamCard = ({
|
||||
rank,
|
||||
team,
|
||||
stats,
|
||||
games,
|
||||
}: {
|
||||
rank: number;
|
||||
team: TeamsFieldsFragment;
|
||||
stats?: TeamStats;
|
||||
games?: TeamGame[];
|
||||
}) => {
|
||||
const t = useT();
|
||||
|
||||
const lastGames = take(
|
||||
orderBy(
|
||||
games?.map((g) => ({
|
||||
rank: g.team.rank,
|
||||
metric: g.team.rewardMetric,
|
||||
epoch: g.epoch,
|
||||
})),
|
||||
(i) => i.epoch,
|
||||
'desc'
|
||||
),
|
||||
5
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'gap-6 grid grid-cols-1 grid-rows-1',
|
||||
'md:grid-cols-3'
|
||||
)}
|
||||
>
|
||||
{/** Card */}
|
||||
<Box
|
||||
backgroundImage={team.avatarUrl || getFallbackAvatar(team.teamId)}
|
||||
className="flex flex-col items-center gap-3 min-w-[80px] lg:min-w-[112px]"
|
||||
>
|
||||
<TeamAvatar teamId={team.teamId} imgUrl={team.avatarUrl} />
|
||||
<h1 className="calt lg:text-2xl" data-testid="team-name">
|
||||
{team.name}
|
||||
</h1>
|
||||
{games && <FavoriteGame games={games} noLabel />}
|
||||
<TradingAnchorButton
|
||||
size="extra-small"
|
||||
intent={Intent.Primary}
|
||||
href={Links.COMPETITIONS_TEAM(team.teamId)}
|
||||
>
|
||||
{t('Profile')}
|
||||
</TradingAnchorButton>
|
||||
<UpdateTeamButton team={team} size="extra-small" />
|
||||
</Box>
|
||||
|
||||
{/** Tiles */}
|
||||
<Box className="w-full md:col-span-2">
|
||||
<div
|
||||
className={classNames(
|
||||
'grid gap-3 w-full mb-4',
|
||||
'md:grid-cols-3 md:grid-rows-2',
|
||||
'grid-cols-2 grid-rows-3'
|
||||
)}
|
||||
>
|
||||
<Stat
|
||||
className="flex flex-col-reverse"
|
||||
value={rank}
|
||||
label={t('Rank')}
|
||||
valueTestId="team-rank"
|
||||
/>
|
||||
<Stat
|
||||
className="flex flex-col-reverse"
|
||||
value={team.totalMembers || 0}
|
||||
label={t('Members')}
|
||||
valueTestId="members-count-stat"
|
||||
/>
|
||||
<Stat
|
||||
className="flex flex-col-reverse"
|
||||
value={stats?.totalGamesPlayed || 0}
|
||||
label={t('Total games')}
|
||||
valueTestId="total-games-stat"
|
||||
/>
|
||||
<Stat
|
||||
className="flex flex-col-reverse"
|
||||
value={
|
||||
stats?.totalQuantumVolume
|
||||
? formatNumberRounded(
|
||||
new BigNumber(stats.totalQuantumVolume || 0),
|
||||
'1e3'
|
||||
)
|
||||
: 0
|
||||
}
|
||||
label={t('Total volume')}
|
||||
valueTestId="total-volume-stat"
|
||||
/>
|
||||
<Stat
|
||||
className="flex flex-col-reverse"
|
||||
value={
|
||||
stats?.totalQuantumRewards
|
||||
? formatNumberRounded(
|
||||
new BigNumber(stats.totalQuantumRewards || 0),
|
||||
'1e3'
|
||||
)
|
||||
: 0
|
||||
}
|
||||
label={t('Rewards paid out')}
|
||||
valueTestId="rewards-paid-stat"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<dl className="w-full pt-4 border-t border-vega-clight-700 dark:border-vega-cdark-700">
|
||||
<dt className="mb-1 text-sm text-muted">
|
||||
{t('Last {{games}} games result', {
|
||||
replace: { games: lastGames.length || '' },
|
||||
})}
|
||||
</dt>
|
||||
<dd className="flex flex-row flex-wrap gap-2">
|
||||
{lastGames.length === 0 && t('None available')}
|
||||
{lastGames.map((game, i) => (
|
||||
<Tooltip key={i} description={DispatchMetricLabels[game.metric]}>
|
||||
<button className="cursor-help text-sm bg-vega-clight-700 dark:bg-vega-cdark-700 px-2 py-1 rounded-full">
|
||||
<RankLabel rank={game.rank} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
))}
|
||||
</dd>
|
||||
</dl>
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the english ordinal for given rank only if the current language is set
|
||||
* to english.
|
||||
*/
|
||||
const RankLabel = ({ rank }: { rank: number }) => {
|
||||
const t = useT();
|
||||
return t('place', { count: rank, ordinal: true });
|
||||
};
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
} from '../../lib/hooks/use-team';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { DispatchMetricLabels, type DispatchMetric } from '@vegaprotocol/types';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export const TeamStats = ({
|
||||
stats,
|
||||
@@ -103,13 +102,7 @@ const LatestResults = ({ games }: { games: TeamGame[] }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const FavoriteGame = ({
|
||||
games,
|
||||
noLabel = false,
|
||||
}: {
|
||||
games: TeamGame[];
|
||||
noLabel?: boolean;
|
||||
}) => {
|
||||
const FavoriteGame = ({ games }: { games: TeamGame[] }) => {
|
||||
const t = useT();
|
||||
|
||||
const rewardMetrics = games.map(
|
||||
@@ -135,13 +128,7 @@ export const FavoriteGame = ({
|
||||
|
||||
return (
|
||||
<dl className="flex flex-col gap-1">
|
||||
<dt
|
||||
className={classNames('text-muted text-sm', {
|
||||
hidden: noLabel,
|
||||
})}
|
||||
>
|
||||
{t('Favorite game')}
|
||||
</dt>
|
||||
<dt className="text-muted text-sm">{t('Favorite game')}</dt>
|
||||
<dd>
|
||||
<Pill className="inline-flex items-center gap-1 bg-transparent text-sm">
|
||||
<VegaIcon
|
||||
@@ -155,7 +142,7 @@ export const FavoriteGame = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const StatSection = ({ children }: { children: ReactNode }) => {
|
||||
const StatSection = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<section className="flex flex-col lg:flex-row gap-4 lg:gap-8">
|
||||
{children}
|
||||
@@ -163,11 +150,11 @@ export const StatSection = ({ children }: { children: ReactNode }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const StatSectionSeparator = () => {
|
||||
const StatSectionSeparator = () => {
|
||||
return <div className="hidden md:block border-r border-default" />;
|
||||
};
|
||||
|
||||
export const StatList = ({ children }: { children: ReactNode }) => {
|
||||
const StatList = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<dl className="grid grid-cols-2 md:flex gap-4 md:gap-6 lg:gap-8 whitespace-nowrap">
|
||||
{children}
|
||||
@@ -175,21 +162,19 @@ export const StatList = ({ children }: { children: ReactNode }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Stat = ({
|
||||
const Stat = ({
|
||||
value,
|
||||
label,
|
||||
tooltip,
|
||||
valueTestId,
|
||||
className,
|
||||
}: {
|
||||
value: ReactNode;
|
||||
label: ReactNode;
|
||||
tooltip?: string;
|
||||
valueTestId?: string;
|
||||
className?: classNames.Argument;
|
||||
}) => {
|
||||
return (
|
||||
<div className={classNames(className)}>
|
||||
<div>
|
||||
<dd className="text-3xl lg:text-4xl" data-testid={valueTestId}>
|
||||
{value}
|
||||
</dd>
|
||||
|
||||
@@ -152,11 +152,7 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
||||
if (!enrichedTransfers || !enrichedTransfers.length) return null;
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={t('Active rewards')}
|
||||
className="lg:col-span-full"
|
||||
data-testid="active-rewards-card"
|
||||
>
|
||||
<Card title={t('Active rewards')} className="lg:col-span-full">
|
||||
{enrichedTransfers.length > 1 && (
|
||||
<TradingInput
|
||||
onChange={(e) =>
|
||||
@@ -375,7 +371,6 @@ export const ActiveRewardCard = ({
|
||||
'rounded-lg',
|
||||
gradientClassName
|
||||
)}
|
||||
data-testid="active-rewards-card"
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
@@ -387,7 +382,7 @@ export const ActiveRewardCard = ({
|
||||
<div className="flex flex-col gap-2 items-center text-center">
|
||||
<EntityIcon transfer={transfer} />
|
||||
{entityScope && (
|
||||
<span className="text-muted text-xs" data-testid="entity-scope">
|
||||
<span className="text-muted text-xs">
|
||||
{EntityScopeLabelMapping[entityScope] || t('Unspecified')}
|
||||
</span>
|
||||
)}
|
||||
@@ -395,7 +390,7 @@ export const ActiveRewardCard = ({
|
||||
|
||||
<div className="flex flex-col gap-2 items-center text-center">
|
||||
<h3 className="flex flex-col gap-1 text-2xl shrink-1 text-center">
|
||||
<span className="font-glitch" data-testid="reward-value">
|
||||
<span className="font-glitch">
|
||||
{addDecimalsFormatNumber(
|
||||
transferNode.transfer.amount,
|
||||
transferNode.transfer.asset?.decimals || 0,
|
||||
@@ -416,7 +411,7 @@ export const ActiveRewardCard = ({
|
||||
)}
|
||||
underline={true}
|
||||
>
|
||||
<span className="text-xs" data-testid="distribution-strategy">
|
||||
<span className="text-xs">
|
||||
{
|
||||
DistributionStrategyMapping[
|
||||
dispatchStrategy.distributionStrategy
|
||||
@@ -434,10 +429,7 @@ export const ActiveRewardCard = ({
|
||||
'Number of epochs after distribution to delay vesting of rewards by'
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className="text-muted text-xs whitespace-nowrap"
|
||||
data-testid="locked-for"
|
||||
>
|
||||
<span className="text-muted text-xs whitespace-nowrap">
|
||||
{t('numberEpochs', '{{count}} epochs', {
|
||||
count: kind.dispatchStrategy?.lockPeriod,
|
||||
})}
|
||||
@@ -446,7 +438,7 @@ export const ActiveRewardCard = ({
|
||||
</div>
|
||||
|
||||
<span className="border-[0.5px] border-gray-700" />
|
||||
<span data-testid="dispatch-metric-info">
|
||||
<span>
|
||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]} •{' '}
|
||||
<Tooltip
|
||||
underline={suspended}
|
||||
@@ -466,8 +458,8 @@ export const ActiveRewardCard = ({
|
||||
<div className="flex items-center gap-8 flex-wrap">
|
||||
{kind.endEpoch && (
|
||||
<span className="flex flex-col">
|
||||
<span className="text-muted text-xs">{t('Ends in')} </span>
|
||||
<span data-testid="ends-in">
|
||||
<span className="text-muted text-xs">{t('Ends in')}</span>
|
||||
<span>
|
||||
{t('numberEpochs', '{{count}} epochs', {
|
||||
count: kind.endEpoch - currentEpoch,
|
||||
})}
|
||||
@@ -478,7 +470,7 @@ export const ActiveRewardCard = ({
|
||||
{
|
||||
<span className="flex flex-col">
|
||||
<span className="text-muted text-xs">{t('Assessed over')}</span>
|
||||
<span data-testid="assessed-over">
|
||||
<span>
|
||||
{t('numberEpochs', '{{count}} epochs', {
|
||||
count: dispatchStrategy.windowLength,
|
||||
})}
|
||||
@@ -521,7 +513,7 @@ const RewardRequirements = ({
|
||||
entity: EntityScopeLabelMapping[dispatchStrategy.entityScope],
|
||||
})}
|
||||
</dt>
|
||||
<dd className="flex items-center gap-1" data-testid="scope">
|
||||
<dd className="flex items-center gap-1">
|
||||
<RewardEntityScope dispatchStrategy={dispatchStrategy} />
|
||||
</dd>
|
||||
</div>
|
||||
@@ -530,10 +522,7 @@ const RewardRequirements = ({
|
||||
<dt className="flex items-center gap-1 text-muted">
|
||||
{t('Staked VEGA')}
|
||||
</dt>
|
||||
<dd
|
||||
className="flex items-center gap-1"
|
||||
data-testid="staking-requirement"
|
||||
>
|
||||
<dd className="flex items-center gap-1">
|
||||
{addDecimalsFormatNumber(
|
||||
dispatchStrategy?.stakingRequirement || 0,
|
||||
assetDecimalPlaces
|
||||
@@ -545,7 +534,7 @@ const RewardRequirements = ({
|
||||
<dt className="flex items-center gap-1 text-muted">
|
||||
{t('Average position')}
|
||||
</dt>
|
||||
<dd className="flex items-center gap-1" data-testid="average-position">
|
||||
<dd className="flex items-center gap-1">
|
||||
{addDecimalsFormatNumber(
|
||||
dispatchStrategy?.notionalTimeWeightedAveragePositionRequirement ||
|
||||
0,
|
||||
|
||||
@@ -59,7 +59,7 @@ def test_filtered_cards(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
next_epoch(vega=vega)
|
||||
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("active-rewards-card")).to_be_visible(timeout=15000)
|
||||
expect(page.locator(".from-vega-cdark-400")).to_be_visible(timeout=15000)
|
||||
governance.submit_oracle_data(
|
||||
wallet=vega.wallet,
|
||||
payload={"trading.terminated": "true"},
|
||||
@@ -67,4 +67,4 @@ def test_filtered_cards(continuous_market, vega: VegaServiceNull, page: Page):
|
||||
)
|
||||
next_epoch(vega=vega)
|
||||
page.reload()
|
||||
expect(page.get_by_test_id("active-rewards-card")).not_to_be_in_viewport()
|
||||
expect(page.locator(".from-vega-cdark-400")).not_to_be_in_viewport()
|
||||
|
||||
@@ -3,7 +3,7 @@ from playwright.sync_api import expect, Page
|
||||
import vega_sim.proto.vega as vega_protos
|
||||
from vega_sim.null_service import VegaServiceNull
|
||||
from conftest import init_vega
|
||||
from actions.utils import next_epoch, change_keys
|
||||
from actions.utils import next_epoch
|
||||
from fixtures.market import setup_continuous_market
|
||||
from conftest import auth_setup, init_page, init_vega, risk_accepted_setup
|
||||
from wallet_config import PARTY_A, PARTY_B, PARTY_C, PARTY_D, MM_WALLET
|
||||
@@ -14,7 +14,6 @@ def vega(request):
|
||||
with init_vega(request) as vega:
|
||||
yield vega
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def team_page(vega, browser, request, setup_teams_and_games):
|
||||
with init_page(vega, browser, request) as page:
|
||||
@@ -24,19 +23,9 @@ def team_page(vega, browser, request, setup_teams_and_games):
|
||||
page.goto(f"/#/competitions/teams/{team_id}")
|
||||
yield page
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def competitions_page(vega, browser, request, setup_teams_and_games):
|
||||
with init_page(vega, browser, request) as page:
|
||||
risk_accepted_setup(page)
|
||||
auth_setup(vega, page)
|
||||
team_id = setup_teams_and_games["team_id"]
|
||||
page.goto(f"/#/competitions/")
|
||||
yield page
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def setup_teams_and_games(vega: VegaServiceNull):
|
||||
tDAI_market = setup_continuous_market(vega, custom_quantum=100000)
|
||||
tDAI_market = setup_continuous_market(vega)
|
||||
tDAI_asset_id = vega.find_asset_id(symbol="tDAI")
|
||||
vega.mint(key_name=PARTY_B.name, asset=tDAI_asset_id, amount=100000)
|
||||
vega.mint(key_name=PARTY_C.name, asset=tDAI_asset_id, amount=100000)
|
||||
@@ -57,18 +46,6 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
|
||||
# list_teams actually returns a dictionary {"team_id": Team}
|
||||
team_id = list(teams.keys())[0]
|
||||
vega.create_referral_set(
|
||||
key_name="market_maker",
|
||||
name="test",
|
||||
team_url="https://vega.xyz",
|
||||
avatar_url="http://placekitten.com/200/200",
|
||||
closed=False,
|
||||
)
|
||||
next_epoch(vega)
|
||||
teams = vega.list_teams()
|
||||
|
||||
team_id_2 = list(teams.keys())[0]
|
||||
vega.apply_referral_code("Key 1", team_id_2)
|
||||
|
||||
vega.apply_referral_code(PARTY_B.name, team_id)
|
||||
|
||||
@@ -86,7 +63,7 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
|
||||
current_epoch = vega.statistics().epoch_seq
|
||||
game_start = current_epoch + 1
|
||||
game_end = current_epoch + 14
|
||||
game_end = current_epoch + 11
|
||||
|
||||
current_epoch = vega.statistics().epoch_seq
|
||||
print(f"[EPOCH: {current_epoch}] creating recurring transfer")
|
||||
@@ -107,42 +84,9 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
factor=1.0,
|
||||
start_epoch=game_start,
|
||||
end_epoch=game_end,
|
||||
window_length=15,
|
||||
)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
vega.recurring_transfer(
|
||||
from_key_name=PARTY_B.name,
|
||||
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
|
||||
to_account_type=vega_protos.vega.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
||||
asset=tDAI_asset_id,
|
||||
reference="reward",
|
||||
asset_for_metric=tDAI_asset_id,
|
||||
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
|
||||
entity_scope=vega_protos.vega.ENTITY_SCOPE_INDIVIDUALS,
|
||||
individual_scope=vega_protos.vega.INDIVIDUAL_SCOPE_IN_TEAM,
|
||||
n_top_performers=1,
|
||||
amount=100,
|
||||
factor=1.0,
|
||||
window_length=15
|
||||
)
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
vega.recurring_transfer(
|
||||
from_key_name=PARTY_C.name,
|
||||
from_account_type=vega_protos.vega.ACCOUNT_TYPE_GENERAL,
|
||||
to_account_type=vega_protos.vega.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES,
|
||||
asset=tDAI_asset_id,
|
||||
reference="reward",
|
||||
asset_for_metric=tDAI_asset_id,
|
||||
metric=vega_protos.vega.DISPATCH_METRIC_MAKER_FEES_PAID,
|
||||
entity_scope=vega_protos.vega.ENTITY_SCOPE_INDIVIDUALS,
|
||||
individual_scope=vega_protos.vega.INDIVIDUAL_SCOPE_NOT_IN_TEAM,
|
||||
n_top_performers=1,
|
||||
amount=100,
|
||||
factor=1.0,
|
||||
window_length=15
|
||||
window_length=10
|
||||
)
|
||||
|
||||
next_epoch(vega)
|
||||
print(f"[EPOCH: {vega.statistics().epoch_seq}] starting order activity")
|
||||
|
||||
@@ -169,22 +113,6 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
side="SIDE_BUY",
|
||||
volume=1,
|
||||
)
|
||||
vega.submit_order(
|
||||
trading_key="Key 1",
|
||||
market_id=tDAI_market,
|
||||
order_type="TYPE_MARKET",
|
||||
time_in_force="TIME_IN_FORCE_IOC",
|
||||
side="SIDE_BUY",
|
||||
volume=1,
|
||||
)
|
||||
vega.submit_order(
|
||||
trading_key="market_maker",
|
||||
market_id=tDAI_market,
|
||||
order_type="TYPE_MARKET",
|
||||
time_in_force="TIME_IN_FORCE_IOC",
|
||||
side="SIDE_BUY",
|
||||
volume=1,
|
||||
)
|
||||
next_epoch(vega)
|
||||
print(f"[EPOCH: {vega.statistics().epoch_seq}] {i} epoch passed")
|
||||
|
||||
@@ -192,7 +120,6 @@ def setup_teams_and_games(vega: VegaServiceNull):
|
||||
"market_id": tDAI_market,
|
||||
"asset_id": tDAI_asset_id,
|
||||
"team_id": team_id,
|
||||
"team_id_2": team_id_2,
|
||||
"team_name": team_name,
|
||||
}
|
||||
|
||||
@@ -209,103 +136,66 @@ def create_team(vega: VegaServiceNull):
|
||||
|
||||
return team_name
|
||||
|
||||
|
||||
def test_team_page_games_table(team_page: Page):
|
||||
team_page.pause()
|
||||
team_page.get_by_test_id("games-toggle").click()
|
||||
expect(team_page.get_by_test_id("games-toggle")).to_have_text("Games (1)")
|
||||
expect(team_page.get_by_test_id("rank-0")).to_have_text("2")
|
||||
expect(team_page.get_by_test_id("epoch-0")).to_have_text("19")
|
||||
expect(team_page.get_by_test_id("rank-0")).to_have_text("1")
|
||||
expect(team_page.get_by_test_id("epoch-0")).to_have_text("18")
|
||||
expect(team_page.get_by_test_id("type-0")).to_have_text("Price maker fees paid")
|
||||
expect(team_page.get_by_test_id("amount-0")).to_have_text("74")
|
||||
expect(team_page.get_by_test_id("participatingTeams-0")).to_have_text("2")
|
||||
expect(team_page.get_by_test_id("participatingMembers-0")).to_have_text("4")
|
||||
|
||||
expect(team_page.get_by_test_id("amount-0")).to_have_text("100,000,000")
|
||||
expect(team_page.get_by_test_id("participatingTeams-0")).to_have_text(
|
||||
"1"
|
||||
)
|
||||
expect(team_page.get_by_test_id("participatingMembers-0")).to_have_text(
|
||||
"2"
|
||||
)
|
||||
|
||||
def test_team_page_members_table(team_page: Page):
|
||||
team_page.get_by_test_id("members-toggle").click()
|
||||
expect(team_page.get_by_test_id("members-toggle")).to_have_text("Members (4)")
|
||||
expect(team_page.get_by_test_id("referee-0")).to_be_visible()
|
||||
expect(team_page.get_by_test_id("joinedAt-0")).to_be_visible()
|
||||
expect(team_page.get_by_test_id("joinedAtEpoch-0")).to_have_text("9")
|
||||
expect(team_page.get_by_test_id("joinedAtEpoch-0")).to_have_text("8")
|
||||
|
||||
|
||||
def test_team_page_headline(team_page: Page, setup_teams_and_games):
|
||||
def test_team_page_headline(team_page: Page, setup_teams_and_games
|
||||
):
|
||||
team_name = setup_teams_and_games["team_name"]
|
||||
expect(team_page.get_by_test_id("team-name")).to_have_text(team_name)
|
||||
expect(team_page.get_by_test_id("members-count-stat")).to_have_text("4")
|
||||
|
||||
expect(team_page.get_by_test_id("total-games-stat")).to_have_text("2")
|
||||
expect(team_page.get_by_test_id("total-games-stat")).to_have_text(
|
||||
"1"
|
||||
)
|
||||
|
||||
# TODO this still seems wrong as its always 0
|
||||
expect(team_page.get_by_test_id("total-volume-stat")).to_have_text("0")
|
||||
expect(team_page.get_by_test_id("total-volume-stat")).to_have_text(
|
||||
"0"
|
||||
)
|
||||
|
||||
expect(team_page.get_by_test_id("rewards-paid-stat")).to_have_text("214")
|
||||
|
||||
|
||||
def test_switch_teams(team_page: Page, vega: VegaServiceNull):
|
||||
team_page.get_by_test_id("switch-team-button").click()
|
||||
team_page.get_by_test_id("confirm-switch-button").click()
|
||||
expect(team_page.get_by_test_id("dialog-content").first).to_be_visible()
|
||||
vega.wait_fn(1)
|
||||
vega.wait_for_total_catchup()
|
||||
next_epoch(vega=vega)
|
||||
team_page.reload()
|
||||
expect(team_page.get_by_test_id("members-count-stat")).to_have_text("5")
|
||||
expect(team_page.get_by_test_id("rewards-paid-stat")).to_have_text(
|
||||
"100m"
|
||||
)
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def competitions_page(vega, browser, request):
|
||||
with init_page(vega, browser, request) as page:
|
||||
risk_accepted_setup(page)
|
||||
auth_setup(vega, page)
|
||||
yield page
|
||||
|
||||
def test_leaderboard(competitions_page: Page, setup_teams_and_games):
|
||||
team_name = setup_teams_and_games["team_name"]
|
||||
competitions_page.reload()
|
||||
expect(
|
||||
competitions_page.get_by_test_id("rank-0").locator(".text-yellow-300")
|
||||
).to_have_count(1)
|
||||
expect(
|
||||
competitions_page.get_by_test_id("rank-1").locator(".text-vega-clight-500")
|
||||
).to_have_count(1)
|
||||
expect(competitions_page.get_by_test_id("team-1")).to_have_text(team_name)
|
||||
expect(competitions_page.get_by_test_id("status-1")).to_have_text("Open")
|
||||
competitions_page.goto(f"/#/competitions/")
|
||||
expect(competitions_page.get_by_test_id("rank-0").locator(".text-yellow-300")).to_have_count(1)
|
||||
expect(competitions_page.get_by_test_id("team-0")).to_have_text(team_name)
|
||||
expect(competitions_page.get_by_test_id("status-0")).to_have_text("Open")
|
||||
|
||||
expect(competitions_page.get_by_test_id("earned-1")).to_have_text("160")
|
||||
expect(competitions_page.get_by_test_id("games-1")).to_have_text("2")
|
||||
expect(competitions_page.get_by_test_id("earned-0")).to_have_text("100,000,000")
|
||||
expect(competitions_page.get_by_test_id("games-0")).to_have_text("1")
|
||||
|
||||
# TODO still odd that this is 0
|
||||
expect(competitions_page.get_by_test_id("volume-0")).to_have_text("-")
|
||||
|
||||
|
||||
def test_game_card(competitions_page: Page):
|
||||
expect(competitions_page.get_by_test_id("active-rewards-card")).to_have_count(2)
|
||||
game_1 = competitions_page.get_by_test_id("active-rewards-card").first
|
||||
expect(game_1).to_be_visible()
|
||||
expect(game_1.get_by_test_id("entity-scope")).to_have_text("Individual")
|
||||
expect(game_1.get_by_test_id("locked-for")).to_have_text("1 epoch")
|
||||
expect(game_1.get_by_test_id("reward-value")).to_have_text("100.00")
|
||||
expect(game_1.get_by_test_id("distribution-strategy")).to_have_text("Pro rata")
|
||||
expect(game_1.get_by_test_id("dispatch-metric-info")).to_have_text("Price maker fees paid • ")
|
||||
expect(game_1.get_by_test_id("assessed-over")).to_have_text("15 epochs")
|
||||
expect(game_1.get_by_test_id("scope")).to_have_text("In team")
|
||||
expect(game_1.get_by_test_id("staking-requirement")).to_have_text("0.00")
|
||||
expect(game_1.get_by_test_id("average-position")).to_have_text("0.00")
|
||||
|
||||
|
||||
def test_create_team(competitions_page: Page, vega: VegaServiceNull):
|
||||
change_keys(competitions_page, vega, "market_maker_2")
|
||||
competitions_page.get_by_test_id("create-public-team-button").click()
|
||||
competitions_page.get_by_test_id("team-name-input").fill("e2e")
|
||||
competitions_page.get_by_test_id("team-url-input").fill("https://vega.xyz")
|
||||
competitions_page.get_by_test_id("avatar-url-input").fill(
|
||||
"http://placekitten.com/200/200"
|
||||
)
|
||||
competitions_page.get_by_test_id("team-form-submit-button").click()
|
||||
expect(competitions_page.get_by_test_id("team-form-submit-button")).to_have_text(
|
||||
"Confirming transaction..."
|
||||
)
|
||||
vega.wait_fn(2)
|
||||
vega.wait_for_total_catchup()
|
||||
expect(
|
||||
competitions_page.get_by_test_id("team-creation-success-message")
|
||||
).to_be_visible()
|
||||
expect(competitions_page.get_by_test_id("team-id-display")).to_be_visible()
|
||||
expect(competitions_page.get_by_test_id("team-id-display")).to_be_visible()
|
||||
competitions_page.get_by_test_id("view-team-button").click()
|
||||
expect(competitions_page.get_by_test_id("team-name")).to_have_text("e2e")
|
||||
|
||||
#TODO def test_games(competitions_page: Page):
|
||||
#TODO currently no games appear which i think is a bug
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
fragment TeamsFields on Team {
|
||||
teamId
|
||||
referrer
|
||||
name
|
||||
teamUrl
|
||||
avatarUrl
|
||||
createdAt
|
||||
createdAtEpoch
|
||||
closed
|
||||
totalMembers
|
||||
}
|
||||
|
||||
query Teams($teamId: ID, $partyId: ID) {
|
||||
teams(teamId: $teamId, partyId: $partyId) {
|
||||
edges {
|
||||
node {
|
||||
...TeamsFields
|
||||
teamId
|
||||
referrer
|
||||
name
|
||||
teamUrl
|
||||
avatarUrl
|
||||
createdAt
|
||||
createdAtEpoch
|
||||
closed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-18
@@ -3,40 +3,33 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type TeamsFieldsFragment = { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, totalMembers: number };
|
||||
|
||||
export type TeamsQueryVariables = Types.Exact<{
|
||||
teamId?: Types.InputMaybe<Types.Scalars['ID']>;
|
||||
partyId?: Types.InputMaybe<Types.Scalars['ID']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type TeamsQuery = { __typename?: 'Query', teams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, totalMembers: number } }> } | null };
|
||||
export type TeamsQuery = { __typename?: 'Query', teams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean } }> } | null };
|
||||
|
||||
|
||||
export const TeamsFieldsFragmentDoc = gql`
|
||||
fragment TeamsFields on Team {
|
||||
teamId
|
||||
referrer
|
||||
name
|
||||
teamUrl
|
||||
avatarUrl
|
||||
createdAt
|
||||
createdAtEpoch
|
||||
closed
|
||||
totalMembers
|
||||
}
|
||||
`;
|
||||
export const TeamsDocument = gql`
|
||||
query Teams($teamId: ID, $partyId: ID) {
|
||||
teams(teamId: $teamId, partyId: $partyId) {
|
||||
edges {
|
||||
node {
|
||||
...TeamsFields
|
||||
teamId
|
||||
referrer
|
||||
name
|
||||
teamUrl
|
||||
avatarUrl
|
||||
createdAt
|
||||
createdAtEpoch
|
||||
closed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${TeamsFieldsFragmentDoc}`;
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useTeamsQuery__
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import compact from 'lodash/compact';
|
||||
import first from 'lodash/first';
|
||||
import { useTeamsQuery } from './__generated__/Teams';
|
||||
import { useTeam } from './use-team';
|
||||
import { useTeams } from './use-teams';
|
||||
|
||||
export const useMyTeam = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { data: teams } = useTeams();
|
||||
|
||||
const { data: maybeMyTeam } = useTeamsQuery({
|
||||
variables: {
|
||||
partyId: pubKey,
|
||||
},
|
||||
skip: !pubKey,
|
||||
fetchPolicy: 'cache-and-network',
|
||||
});
|
||||
|
||||
const team = first(compact(maybeMyTeam?.teams?.edges.map((n) => n.node)));
|
||||
const rank = teams.findIndex((t) => t.teamId === team?.teamId) + 1;
|
||||
const { games, stats } = useTeam(team?.teamId);
|
||||
|
||||
return { team, stats, games, rank };
|
||||
};
|
||||
@@ -33,7 +33,6 @@ import { PartyActiveOrdersHandler } from './party-active-orders-handler';
|
||||
import { MaybeConnectEagerly } from './maybe-connect-eagerly';
|
||||
import { TransactionHandlers } from './transaction-handlers';
|
||||
import { useT } from '../lib/use-t';
|
||||
import { Test } from './test/test';
|
||||
|
||||
const Title = () => {
|
||||
const t = useT();
|
||||
@@ -136,6 +135,4 @@ function VegaTradingApp(props: AppProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function () {
|
||||
return <Test />;
|
||||
}
|
||||
export default VegaTradingApp;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
export type Chain = {
|
||||
id: string;
|
||||
testnet: boolean;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const fairground = {
|
||||
id: 'vega-fairground-202305051805',
|
||||
testnet: true,
|
||||
name: 'Fairground',
|
||||
};
|
||||
|
||||
export const stagnet = {
|
||||
id: 'vega-stagnet1-202307191148',
|
||||
testnet: true,
|
||||
name: 'Stagnet',
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
import {
|
||||
type Transaction,
|
||||
type TransactionResponse,
|
||||
} from '@vegaprotocol/wallet';
|
||||
|
||||
export enum JsonRpcMethod {
|
||||
ConnectWallet = 'client.connect_wallet',
|
||||
DisconnectWallet = 'client.disconnect_wallet',
|
||||
ListKeys = 'client.list_keys',
|
||||
SignTransaction = 'client.sign_transaction',
|
||||
SendTransaction = 'client.send_transaction',
|
||||
GetChainId = 'client.get_chain_id',
|
||||
}
|
||||
|
||||
export interface IWalletError {
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface TransactionParams {
|
||||
publicKey: string;
|
||||
transaction: Transaction;
|
||||
sendingMode: 'TYPE_SYNC';
|
||||
}
|
||||
|
||||
export interface Connector {
|
||||
id: string;
|
||||
|
||||
connectWallet(chainId: string): Promise<{ success: boolean } | IWalletError>;
|
||||
|
||||
disconnectWallet(): Promise<{ success: boolean } | IWalletError>;
|
||||
|
||||
getChainId(): Promise<{ chainId: string } | IWalletError>;
|
||||
|
||||
listKeys(): Promise<
|
||||
Array<{ publicKey: string; name: string }> | IWalletError
|
||||
>;
|
||||
|
||||
isConnected(): Promise<{ connected: boolean } | IWalletError>;
|
||||
|
||||
sendTransaction(
|
||||
params: TransactionParams
|
||||
): Promise<TransactionResponse | IWalletError>;
|
||||
|
||||
on(event: string, callback: () => void): void;
|
||||
|
||||
off(event: string, callback: () => void): void;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { TransactionParams, type Connector } from '.';
|
||||
|
||||
export class InjectedConnector implements Connector {
|
||||
id = 'injected';
|
||||
|
||||
async connectWallet(chainId: string) {
|
||||
try {
|
||||
await window.vega.connectWallet({ chainId });
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
return { error: 'failed to connect' };
|
||||
}
|
||||
}
|
||||
|
||||
async disconnectWallet() {
|
||||
try {
|
||||
await window.vega.disconnectWallet();
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
return { error: 'failed to disconnect' };
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated, pass chain on connect
|
||||
async getChainId() {
|
||||
try {
|
||||
const res = await window.vega.getChainId();
|
||||
return { chainId: res.chainID };
|
||||
} catch (err) {
|
||||
return { error: 'failed to get chain id' };
|
||||
}
|
||||
}
|
||||
|
||||
async listKeys() {
|
||||
try {
|
||||
const res = await window.vega.listKeys();
|
||||
return res.keys;
|
||||
} catch (err) {
|
||||
return { error: 'failed to list keys' };
|
||||
}
|
||||
}
|
||||
|
||||
async isConnected() {
|
||||
try {
|
||||
const res = await window.vega.isConnected();
|
||||
return { connected: res };
|
||||
} catch (err) {
|
||||
return { error: 'failed to check isConnected' };
|
||||
}
|
||||
}
|
||||
|
||||
async sendTransaction(params: TransactionParams) {
|
||||
try {
|
||||
const res = await window.vega.sendTransaction(params);
|
||||
|
||||
return {
|
||||
transactionHash: res.transactionHash,
|
||||
signature: res.transaction.signature.value,
|
||||
receivedAt: res.receivedAt,
|
||||
sentAt: res.sentAt,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return { error: 'failed to send transaction' };
|
||||
}
|
||||
}
|
||||
|
||||
on(event: 'client.disconnected', callback: () => void) {
|
||||
window.vega.on(event, callback);
|
||||
}
|
||||
|
||||
off(event: 'client.disconnected') {
|
||||
window.vega.off(event);
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import { JsonRpcMethod, type Connector, type TransactionParams } from '.';
|
||||
|
||||
type JsonRpcConnectorConfig = { url: string };
|
||||
|
||||
export class JsonRpcConnector implements Connector {
|
||||
id = 'json-rpc';
|
||||
config: JsonRpcConnectorConfig;
|
||||
requestId: number = 0;
|
||||
token: string | null = null;
|
||||
|
||||
constructor(config: JsonRpcConnectorConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
async connectWallet(desiredChainId: string) {
|
||||
try {
|
||||
const { chainId } = await this.getChainId();
|
||||
|
||||
if (chainId !== desiredChainId) {
|
||||
throw new Error('incorrect chain id');
|
||||
}
|
||||
|
||||
const { response } = await this.request(JsonRpcMethod.ConnectWallet, {
|
||||
hostname: window.location.hostname,
|
||||
});
|
||||
|
||||
const token = response.headers.get('Authorization');
|
||||
|
||||
if (response.ok && token) {
|
||||
this.token = token;
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
return { error: 'failed to connect' };
|
||||
} catch (err) {
|
||||
return { error: 'failed to connect' };
|
||||
}
|
||||
}
|
||||
|
||||
async disconnectWallet() {
|
||||
try {
|
||||
await this.request(JsonRpcMethod.DisconnectWallet);
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
return { error: 'failed to disconnect' };
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated, pass chain on connect
|
||||
async getChainId() {
|
||||
try {
|
||||
const { data } = await this.request(JsonRpcMethod.GetChainId);
|
||||
return { chainId: data.result.chainID };
|
||||
} catch (err) {
|
||||
return { error: 'failed to get chain id' };
|
||||
}
|
||||
}
|
||||
|
||||
async listKeys() {
|
||||
try {
|
||||
const { data } = await this.request(JsonRpcMethod.ListKeys);
|
||||
return data.result.keys as Array<{ publicKey: string; name: string }>;
|
||||
} catch (err) {
|
||||
return { error: 'failed to list keys' };
|
||||
}
|
||||
}
|
||||
|
||||
async isConnected() {
|
||||
try {
|
||||
await this.listKeys();
|
||||
return { connected: true };
|
||||
} catch (err) {
|
||||
return { error: 'failed to check isConnected' };
|
||||
}
|
||||
}
|
||||
|
||||
async sendTransaction(params: TransactionParams) {
|
||||
try {
|
||||
const { data } = await this.request(
|
||||
JsonRpcMethod.SendTransaction,
|
||||
params
|
||||
);
|
||||
|
||||
return {
|
||||
transactionHash: data.result.transactionHash,
|
||||
signature: data.result.transaction.signature.value,
|
||||
receivedAt: data.result.receivedAt,
|
||||
sentAt: data.result.sentAt,
|
||||
};
|
||||
} catch (err) {
|
||||
return { error: 'failed to send transaction' };
|
||||
}
|
||||
}
|
||||
|
||||
private async request(method: JsonRpcMethod, params?: any) {
|
||||
const headers = new Headers();
|
||||
|
||||
if (this.token) {
|
||||
headers.set('Authorization', this.token);
|
||||
}
|
||||
|
||||
const response = await fetch(this.config.url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
id: `${this.requestId++}`,
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params,
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
return {
|
||||
data,
|
||||
response,
|
||||
};
|
||||
}
|
||||
|
||||
on() {
|
||||
console.warn('events are not supported in json rpc wallet');
|
||||
}
|
||||
|
||||
off() {
|
||||
console.warn('events are not supported in json rpc wallet');
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
import { JsonRpcMethod, type Connector, type TransactionParams } from '.';
|
||||
|
||||
enum EthereumMethod {
|
||||
RequestSnaps = 'wallet_requestSnaps',
|
||||
GetSnaps = 'wallet_getSnaps',
|
||||
InvokeSnap = 'wallet_invokeSnap',
|
||||
}
|
||||
|
||||
type SnapConfig = {
|
||||
id: string;
|
||||
node: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export class SnapConnector implements Connector {
|
||||
id = 'snap';
|
||||
|
||||
config: SnapConfig;
|
||||
|
||||
constructor(config: SnapConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
async connectWallet(desiredChainId: string) {
|
||||
try {
|
||||
await this.requestSnap();
|
||||
|
||||
const { chainId } = await this.getChainId();
|
||||
|
||||
if (chainId !== desiredChainId) {
|
||||
throw new Error('incorrect chain id');
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
return { error: 'failed to connect' };
|
||||
}
|
||||
}
|
||||
|
||||
async disconnectWallet() {
|
||||
console.warn('disconnectWallet not implemented');
|
||||
return { error: 'failed to disconnect' };
|
||||
}
|
||||
|
||||
// deprecated, pass chain on connect
|
||||
async getChainId() {
|
||||
try {
|
||||
const res = await this.invokeSnap(JsonRpcMethod.GetChainId, {
|
||||
networkEndpoints: [this.config.node],
|
||||
});
|
||||
return { chainId: res.chainID };
|
||||
} catch (err) {
|
||||
return { error: 'failed to get chain id' };
|
||||
}
|
||||
}
|
||||
|
||||
async listKeys() {
|
||||
try {
|
||||
const res = await this.invokeSnap(JsonRpcMethod.ListKeys);
|
||||
return res.keys as Array<{ publicKey: string; name: string }>;
|
||||
} catch (err) {
|
||||
return { error: 'failed to list keys' };
|
||||
}
|
||||
}
|
||||
|
||||
async isConnected() {
|
||||
console.warn('isConnected not implemented');
|
||||
return { error: 'failed to check if connected' };
|
||||
}
|
||||
|
||||
async sendTransaction(params: TransactionParams) {
|
||||
try {
|
||||
const res = await this.invokeSnap(JsonRpcMethod.SendTransaction, {
|
||||
publicKey: params.publicKey,
|
||||
sendingMode: params.sendingMode,
|
||||
transaction: params.transaction,
|
||||
networkEndpoints: [this.config.node],
|
||||
});
|
||||
|
||||
return {
|
||||
transactionHash: res.transactionHash,
|
||||
signature: res.transaction.signature.value,
|
||||
receivedAt: res.receivedAt,
|
||||
sentAt: res.sentAt,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return { error: 'failed to send transaction' };
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// Snap methods
|
||||
////////////////////////////////////
|
||||
|
||||
async requestSnap() {
|
||||
const res = await this.request(EthereumMethod.RequestSnaps, {
|
||||
[this.config.id]: {
|
||||
version: this.config.version,
|
||||
},
|
||||
});
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
async getSnap() {
|
||||
const snaps = await this.request(EthereumMethod.GetSnaps);
|
||||
return Object.values(snaps).find(
|
||||
(s) => s.id === this.config.id && s.version === this.config.version
|
||||
);
|
||||
}
|
||||
|
||||
async invokeSnap(method: JsonRpcMethod, params?: any) {
|
||||
return await this.request(EthereumMethod.InvokeSnap, {
|
||||
snapId: this.config.id,
|
||||
request: {
|
||||
method: method,
|
||||
params,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async request(method: EthereumMethod, params?: any) {
|
||||
if (!window.ethereum) {
|
||||
throw new Error('no window.ethereum');
|
||||
}
|
||||
|
||||
// @ts-ignore ethereum types a bit mangled from web3-react
|
||||
return window.ethereum.request({
|
||||
method,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
on() {
|
||||
console.warn('events are not supported in json rpc wallet');
|
||||
}
|
||||
|
||||
off() {
|
||||
console.warn('events are not supported in json rpc wallet');
|
||||
}
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
import { StoreApi, createStore } from 'zustand/vanilla';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { InjectedConnector } from './injected-connector';
|
||||
import { JsonRpcConnector } from './json-rpc-connector';
|
||||
import { SnapConnector } from './snap-connector';
|
||||
import { Chain, fairground, stagnet } from './chains';
|
||||
import { Connector, TransactionParams } from '.';
|
||||
import {
|
||||
PropsWithChildren,
|
||||
createContext,
|
||||
createElement,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import { TransactionResponse } from '@vegaprotocol/wallet';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
const injected = new InjectedConnector();
|
||||
const jsonRpc = new JsonRpcConnector({
|
||||
url: 'http://localhost:1789/api/v2/requests',
|
||||
});
|
||||
const snap = new SnapConnector({
|
||||
node: 'https://api.n08.testnet.vega.rocks',
|
||||
id: 'npm:@vegaprotocol/snap',
|
||||
version: '0.3.1',
|
||||
});
|
||||
|
||||
type Key = {
|
||||
publicKey: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type Store = {
|
||||
chainId: string;
|
||||
status: 'disconnected' | 'connecting' | 'connected';
|
||||
current: string | undefined;
|
||||
keys: Key[];
|
||||
setKeys: (keys: Key[]) => void;
|
||||
};
|
||||
|
||||
type Config = { chains: Chain[]; connectors: Connector[] };
|
||||
|
||||
type Wallet = {
|
||||
store: StoreApi<Store>;
|
||||
connectors: Connector[];
|
||||
connect: (id: string) => Promise<void>;
|
||||
disconnect: () => Promise<void>;
|
||||
sendTransaction: (params: TransactionParams) => Promise<TransactionResponse>;
|
||||
};
|
||||
|
||||
function createConfig(cfg: Config): Wallet {
|
||||
const connectors = createStore(() => cfg.connectors);
|
||||
|
||||
const store = createStore<Store>((set) => ({
|
||||
chainId: cfg.chains[0].id,
|
||||
status: 'disconnected',
|
||||
current: undefined,
|
||||
keys: [],
|
||||
setKeys: (keys) => {
|
||||
set({ keys });
|
||||
},
|
||||
}));
|
||||
|
||||
async function connect(id: string) {
|
||||
if (store.getState().status === 'connecting') {
|
||||
return;
|
||||
}
|
||||
|
||||
const connector = connectors.getState().find((x) => x.id === id);
|
||||
|
||||
if (!connector) return;
|
||||
|
||||
try {
|
||||
store.setState({ status: 'connecting', current: id });
|
||||
|
||||
const connectWalletRes = await connector.connectWallet(
|
||||
store.getState().chainId
|
||||
);
|
||||
|
||||
if ('error' in connectWalletRes) {
|
||||
throw new Error('failed to connect');
|
||||
}
|
||||
|
||||
const listKeysRes = await connector.listKeys();
|
||||
|
||||
if ('error' in listKeysRes) {
|
||||
throw new Error('failed to get keys');
|
||||
}
|
||||
|
||||
store.setState({
|
||||
keys: listKeysRes,
|
||||
status: 'connected',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
store.setState({ status: 'disconnected', current: undefined, keys: [] });
|
||||
}
|
||||
}
|
||||
|
||||
async function disconnect() {
|
||||
const connector = connectors
|
||||
.getState()
|
||||
.find((x) => x.id === store.getState().current);
|
||||
|
||||
if (!connector) return;
|
||||
|
||||
store.setState({ status: 'disconnected', current: undefined, keys: [] });
|
||||
}
|
||||
|
||||
async function sendTransaction(params: TransactionParams) {
|
||||
const connector = connectors
|
||||
.getState()
|
||||
.find((x) => x.id === store.getState().current);
|
||||
|
||||
if (!connector) return;
|
||||
|
||||
try {
|
||||
const res = await connector.sendTransaction(params);
|
||||
|
||||
return res;
|
||||
console.log('res', res);
|
||||
} catch (err) {
|
||||
return {
|
||||
error: 'failed to send',
|
||||
};
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
store,
|
||||
connect,
|
||||
disconnect,
|
||||
sendTransaction,
|
||||
|
||||
get connectors() {
|
||||
return connectors.getState();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const config = createConfig({
|
||||
chains: [fairground, stagnet],
|
||||
connectors: [injected, jsonRpc, snap],
|
||||
});
|
||||
|
||||
function useWallet<T>(selector: (store: Store) => T) {
|
||||
const store = useStore(config.store, selector);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
function useConfig() {
|
||||
const context = useContext(VegaWalletContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('must be used within VegaWalletProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
function useConnect() {
|
||||
const config = useConfig();
|
||||
return {
|
||||
connectors: config.connectors,
|
||||
connect: config.connect,
|
||||
};
|
||||
}
|
||||
|
||||
function useDisconnect() {
|
||||
const config = useConfig();
|
||||
return {
|
||||
disconnect: config.disconnect,
|
||||
};
|
||||
}
|
||||
|
||||
function useSendTransaction() {
|
||||
const config = useConfig();
|
||||
return {
|
||||
sendTransaction: config.sendTransaction,
|
||||
};
|
||||
}
|
||||
|
||||
const VegaWalletContext = createContext<Wallet | undefined>(undefined);
|
||||
|
||||
function VegaWalletProvider({
|
||||
children,
|
||||
config,
|
||||
}: PropsWithChildren<{ config: Wallet }>) {
|
||||
return createElement(VegaWalletContext.Provider, { value: config }, children);
|
||||
}
|
||||
|
||||
export function Test() {
|
||||
return (
|
||||
<VegaWalletProvider config={config}>
|
||||
<App />
|
||||
</VegaWalletProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { connectors, connect } = useConnect();
|
||||
const { disconnect } = useDisconnect();
|
||||
const { sendTransaction } = useSendTransaction();
|
||||
const status = useWallet((store) => store.status);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => setOpen(true)}>Connect</button>
|
||||
<Dialog open={open}>
|
||||
<div>
|
||||
{status === 'disconnected' && (
|
||||
<div className="flex gap-2">
|
||||
{connectors.map((c) => (
|
||||
<button
|
||||
key={c.id}
|
||||
onClick={async () => {
|
||||
try {
|
||||
await connect(c.id);
|
||||
setTimeout(() => {
|
||||
setOpen(false);
|
||||
}, 1000);
|
||||
} catch (err) {}
|
||||
}}
|
||||
>
|
||||
connect {c.id}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{status === 'connecting' && <div>Approve connection in wallet</div>}
|
||||
{status === 'connected' && <div>Connected!</div>}
|
||||
</div>
|
||||
</Dialog>
|
||||
<hr className="border-t pt-2 mt-2" />
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
<button onClick={() => disconnect()}>diconnectWallet</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
const fromKey =
|
||||
'846b2ed2fff0ddf219a5302a3856f9ac279652c4d92e72e7df762117886e69cc'; // snap
|
||||
const toKey =
|
||||
'5a703397f6ac1f62513af1f5d0237d1b9f8b2c93ef19fbe9fa87771a2b7f55da'; // browser
|
||||
|
||||
const res = await sendTransaction({
|
||||
publicKey: fromKey,
|
||||
sendingMode: 'TYPE_SYNC',
|
||||
transaction: {
|
||||
transfer: {
|
||||
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
to: toKey,
|
||||
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
asset:
|
||||
'16ae5dbb1fd7aa2ddef725703bfe66b3647a4da7b844bfdd04e985756f53d9d6',
|
||||
amount: '100',
|
||||
oneOff: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log(res);
|
||||
}}
|
||||
>
|
||||
submit transfer
|
||||
</button>
|
||||
</div>
|
||||
<div>{status}</div>
|
||||
<Keys />
|
||||
{/* <NoReact /> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Keys = () => {
|
||||
const keys = useWallet((store) => store.keys);
|
||||
|
||||
if (!keys.length) {
|
||||
return <p>No keys</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{keys.map((k) => {
|
||||
return (
|
||||
<li key={k.publicKey}>
|
||||
{k.name} {k.publicKey}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
const NoReact = () => {
|
||||
const divRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!divRef.current) return;
|
||||
const div = divRef.current;
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.addEventListener('click', () => {
|
||||
config.connect('injected'); // should fail
|
||||
});
|
||||
button.textContent = 'Connect injected';
|
||||
|
||||
const status = document.createElement('div');
|
||||
const keys = document.createElement('ul');
|
||||
|
||||
config.store.subscribe((state) => {
|
||||
status.textContent = state.status;
|
||||
|
||||
state.keys.forEach((key) => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = `${key.name} ${key.publicKey}`;
|
||||
keys.appendChild(li);
|
||||
});
|
||||
});
|
||||
|
||||
div.appendChild(button);
|
||||
div.appendChild(status);
|
||||
div.appendChild(keys);
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
<h1>No react</h1>
|
||||
<div ref={divRef} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
import { InjectedConnector } from './injected-connector';
|
||||
import { JsonRpcConnector } from './json-rpc-connector';
|
||||
import { SnapConnector } from './snap-connector';
|
||||
|
||||
export class Wallet {
|
||||
connector?: InjectedConnector | JsonRpcConnector | SnapConnector;
|
||||
|
||||
async connectWallet(
|
||||
connector: InjectedConnector | JsonRpcConnector | SnapConnector
|
||||
) {
|
||||
this.connector = connector;
|
||||
|
||||
const res = await this.connector.connectWallet();
|
||||
|
||||
if (res.success !== true) {
|
||||
// TODO: something better
|
||||
return;
|
||||
}
|
||||
|
||||
const keys = await this.connector.listKeys();
|
||||
console.log(keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
async disconnectWallet() {
|
||||
if (!this.connector) {
|
||||
throw new Error('no connector');
|
||||
}
|
||||
|
||||
await this.connector.disconnectWallet();
|
||||
this.connector = undefined;
|
||||
}
|
||||
|
||||
async listKeys() {
|
||||
if (!this.connector) {
|
||||
throw new Error('no connector');
|
||||
}
|
||||
|
||||
return this.connector.listKeys();
|
||||
}
|
||||
|
||||
async getChainId() {
|
||||
if (!this.connector) {
|
||||
throw new Error('no connector');
|
||||
}
|
||||
|
||||
return this.connector.getChainId();
|
||||
}
|
||||
|
||||
async isConnected() {
|
||||
if (!this.connector) {
|
||||
throw new Error('no connector');
|
||||
}
|
||||
|
||||
return this.connector.isConnected();
|
||||
}
|
||||
|
||||
// sendTransaction(...args: Parameters<typeof window.vega.sendTransaction>) {
|
||||
// if (!this.connector) {
|
||||
// throw new Error('no connector');
|
||||
// }
|
||||
//
|
||||
// return this.connector.sendTransaction(...args);
|
||||
// }
|
||||
}
|
||||
@@ -417,7 +417,6 @@
|
||||
"myVolume_other": "My volume (last {{count}} epochs)",
|
||||
"numberEpochs": "{{count}} epochs",
|
||||
"numberEpochs_one": "{{count}} epoch",
|
||||
"Rewards earned": "Rewards earned",
|
||||
"Rewards paid out": "Rewards paid out",
|
||||
"{{reward}}x": "{{reward}}x",
|
||||
"userActive": "{{active}} trader: {{count}} epochs so far",
|
||||
@@ -432,19 +431,5 @@
|
||||
"{{assetSymbol}} Reward pot": "{{assetSymbol}} Reward pot",
|
||||
"{{checkedAssets}} Assets": "{{checkedAssets}} Assets",
|
||||
"{{distance}} ago": "{{distance}} ago",
|
||||
"{{instrumentCode}} liquidity provision": "{{instrumentCode}} liquidity provision",
|
||||
"My team": "My team",
|
||||
"Profile": "Profile",
|
||||
"Last {{games}} games result_one": "Last game result",
|
||||
"Last {{games}} games result_other": "Last {{games}} games result",
|
||||
"Leaderboard": "Leaderboard",
|
||||
"View all teams": "View all teams",
|
||||
"Competitions": "Competitions",
|
||||
"Be a team player! Participate in games and work together to rake in as much profit to win.": "Be a team player! Participate in games and work together to rake in as much profit to win.",
|
||||
"Create a public team": "Create a public team",
|
||||
"Create a private team": "Create a private team",
|
||||
"Choose a team": "Choose a team",
|
||||
"Join a team": "Join a team",
|
||||
"Solo team / lone wolf": "Solo team / lone wolf",
|
||||
"Choose a team to get involved": "Choose a team to get involved"
|
||||
"{{instrumentCode}} liquidity provision": "{{instrumentCode}} liquidity provision"
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@ declare global {
|
||||
}>;
|
||||
|
||||
on: (event: VegaWalletEvent, callback: () => void) => void;
|
||||
off: (event: VegaWalletEvent) => void;
|
||||
isConnected: () => Promise<boolean>;
|
||||
getChainId: () => Promise<{ chainID: string }>;
|
||||
isConnected?: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
||||
Reference in New Issue
Block a user