feat(trading): add and show key aliases (#5819)
This commit is contained in:
parent
38d13085fb
commit
ad6f0c5798
1
apps/trading/components/profile-dialog/index.ts
Normal file
1
apps/trading/components/profile-dialog/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { ProfileDialog } from './profile-dialog';
|
150
apps/trading/components/profile-dialog/profile-dialog.tsx
Normal file
150
apps/trading/components/profile-dialog/profile-dialog.tsx
Normal file
@ -0,0 +1,150 @@
|
||||
import {
|
||||
Dialog,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Intent,
|
||||
TradingButton,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { useRequired } from '@vegaprotocol/utils';
|
||||
import {
|
||||
useSimpleTransaction,
|
||||
type Status,
|
||||
useVegaWallet,
|
||||
} from '@vegaprotocol/wallet-react';
|
||||
import {
|
||||
usePartyProfilesQuery,
|
||||
type PartyProfilesQuery,
|
||||
} from '../vega-wallet-connect-button/__generated__/PartyProfiles';
|
||||
|
||||
export const ProfileDialog = () => {
|
||||
const t = useT();
|
||||
const { pubKeys } = useVegaWallet();
|
||||
const { data, refetch } = usePartyProfilesQuery({
|
||||
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
||||
skip: pubKeys.length <= 0,
|
||||
});
|
||||
const open = useProfileDialogStore((store) => store.open);
|
||||
const pubKey = useProfileDialogStore((store) => store.pubKey);
|
||||
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
||||
|
||||
const { send, status, error, reset } = useSimpleTransaction({
|
||||
onSuccess: () => {
|
||||
refetch();
|
||||
},
|
||||
});
|
||||
|
||||
const profileEdge = data?.partiesProfilesConnection?.edges.find(
|
||||
(e) => e.node.partyId === pubKey
|
||||
);
|
||||
|
||||
const sendTx = (field: FormFields) => {
|
||||
send({
|
||||
updatePartyProfile: {
|
||||
alias: field.alias,
|
||||
metadata: [],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onChange={() => {
|
||||
setOpen(undefined);
|
||||
reset();
|
||||
}}
|
||||
title={t('Edit profile')}
|
||||
>
|
||||
<ProfileForm
|
||||
profile={profileEdge?.node}
|
||||
status={status}
|
||||
error={error}
|
||||
onSubmit={sendTx}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
interface FormFields {
|
||||
alias: string;
|
||||
}
|
||||
|
||||
type Profile = NonNullable<
|
||||
PartyProfilesQuery['partiesProfilesConnection']
|
||||
>['edges'][number]['node'];
|
||||
|
||||
const ProfileForm = ({
|
||||
profile,
|
||||
onSubmit,
|
||||
status,
|
||||
error,
|
||||
}: {
|
||||
profile: Profile | undefined;
|
||||
onSubmit: (fields: FormFields) => void;
|
||||
status: Status;
|
||||
error: string | undefined;
|
||||
}) => {
|
||||
const t = useT();
|
||||
const required = useRequired();
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<FormFields>({
|
||||
defaultValues: {
|
||||
alias: profile?.alias,
|
||||
},
|
||||
});
|
||||
|
||||
const renderButtonText = () => {
|
||||
if (status === 'requested') {
|
||||
return t('Confirm in wallet...');
|
||||
}
|
||||
|
||||
if (status === 'pending') {
|
||||
return t('Confirming transaction...');
|
||||
}
|
||||
|
||||
return t('Submit');
|
||||
};
|
||||
|
||||
const errorMessage = errors.alias?.message || error;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="mt-3">
|
||||
<FormGroup label="Alias" labelFor="alias">
|
||||
<Input
|
||||
{...register('alias', {
|
||||
validate: {
|
||||
required,
|
||||
},
|
||||
})}
|
||||
/>
|
||||
{errorMessage && (
|
||||
<InputError>
|
||||
<p className="break-words max-w-full first-letter:uppercase">
|
||||
{errorMessage}
|
||||
</p>
|
||||
</InputError>
|
||||
)}
|
||||
|
||||
{status === 'confirmed' && (
|
||||
<p className="mt-2 mb-4 text-sm text-success">
|
||||
{t('Profile updated')}
|
||||
</p>
|
||||
)}
|
||||
</FormGroup>
|
||||
<TradingButton
|
||||
type="submit"
|
||||
intent={Intent.Info}
|
||||
disabled={status === 'requested' || status === 'pending'}
|
||||
>
|
||||
{renderButtonText()}
|
||||
</TradingButton>
|
||||
</form>
|
||||
);
|
||||
};
|
@ -0,0 +1,14 @@
|
||||
query PartyProfiles($partyIds: [ID!]) {
|
||||
partiesProfilesConnection(ids: $partyIds) {
|
||||
edges {
|
||||
node {
|
||||
partyId
|
||||
alias
|
||||
metadata {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
apps/trading/components/vega-wallet-connect-button/__generated__/PartyProfiles.ts
generated
Normal file
57
apps/trading/components/vega-wallet-connect-button/__generated__/PartyProfiles.ts
generated
Normal file
@ -0,0 +1,57 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type PartyProfilesQueryVariables = Types.Exact<{
|
||||
partyIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type PartyProfilesQuery = { __typename?: 'Query', partiesProfilesConnection?: { __typename?: 'PartiesProfilesConnection', edges: Array<{ __typename?: 'PartyProfileEdge', node: { __typename?: 'PartyProfile', partyId: string, alias: string, metadata: Array<{ __typename?: 'Metadata', key: string, value: string }> } }> } | null };
|
||||
|
||||
|
||||
export const PartyProfilesDocument = gql`
|
||||
query PartyProfiles($partyIds: [ID!]) {
|
||||
partiesProfilesConnection(ids: $partyIds) {
|
||||
edges {
|
||||
node {
|
||||
partyId
|
||||
alias
|
||||
metadata {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __usePartyProfilesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `usePartyProfilesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `usePartyProfilesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = usePartyProfilesQuery({
|
||||
* variables: {
|
||||
* partyIds: // value for 'partyIds'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function usePartyProfilesQuery(baseOptions?: Apollo.QueryHookOptions<PartyProfilesQuery, PartyProfilesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<PartyProfilesQuery, PartyProfilesQueryVariables>(PartyProfilesDocument, options);
|
||||
}
|
||||
export function usePartyProfilesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyProfilesQuery, PartyProfilesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<PartyProfilesQuery, PartyProfilesQueryVariables>(PartyProfilesDocument, options);
|
||||
}
|
||||
export type PartyProfilesQueryHookResult = ReturnType<typeof usePartyProfilesQuery>;
|
||||
export type PartyProfilesLazyQueryHookResult = ReturnType<typeof usePartyProfilesLazyQuery>;
|
||||
export type PartyProfilesQueryResult = Apollo.QueryResult<PartyProfilesQuery, PartyProfilesQueryVariables>;
|
@ -1,21 +1,57 @@
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||
import { act, fireEvent, render, screen, within } from '@testing-library/react';
|
||||
import { VegaWalletConnectButton } from './vega-wallet-connect-button';
|
||||
import { truncateByChars } from '@vegaprotocol/utils';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import {
|
||||
mockConfig,
|
||||
MockedWalletProvider,
|
||||
} from '@vegaprotocol/wallet-react/testing';
|
||||
import { MockedProvider, type MockedResponse } from '@apollo/react-testing';
|
||||
import {
|
||||
PartyProfilesDocument,
|
||||
type PartyProfilesQuery,
|
||||
} from './__generated__/PartyProfiles';
|
||||
|
||||
jest.mock('../../lib/hooks/use-get-current-route-id', () => ({
|
||||
useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'),
|
||||
}));
|
||||
|
||||
const key = { publicKey: '123456__123456', name: 'test' };
|
||||
const key2 = { publicKey: 'abcdef__abcdef', name: 'test2' };
|
||||
const keys = [key, key2];
|
||||
const keyProfile = {
|
||||
__typename: 'PartyProfile' as const,
|
||||
partyId: key.publicKey,
|
||||
alias: `${key.name} alias`,
|
||||
metadata: [],
|
||||
};
|
||||
|
||||
const renderComponent = (mockOnClick = jest.fn()) => {
|
||||
const partyProfilesMock: MockedResponse<PartyProfilesQuery> = {
|
||||
request: {
|
||||
query: PartyProfilesDocument,
|
||||
variables: { partyIds: keys.map((k) => k.publicKey) },
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
partiesProfilesConnection: {
|
||||
__typename: 'PartiesProfilesConnection',
|
||||
edges: [
|
||||
{
|
||||
__typename: 'PartyProfileEdge',
|
||||
node: keyProfile,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<MockedProvider mocks={[partyProfilesMock]}>
|
||||
<MockedWalletProvider>
|
||||
<VegaWalletConnectButton onClick={mockOnClick} />
|
||||
</MockedWalletProvider>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -43,10 +79,6 @@ describe('VegaWalletConnectButton', () => {
|
||||
});
|
||||
|
||||
it('should open dropdown and refresh keys when connected', async () => {
|
||||
const key = { publicKey: '123456__123456', name: 'test' };
|
||||
const key2 = { publicKey: 'abcdef__abcdef', name: 'test2' };
|
||||
const keys = [key, key2];
|
||||
|
||||
mockConfig.store.setState({
|
||||
status: 'connected',
|
||||
keys,
|
||||
@ -61,14 +93,22 @@ describe('VegaWalletConnectButton', () => {
|
||||
|
||||
expect(screen.queryByTestId('connect-vega-wallet')).not.toBeInTheDocument();
|
||||
const button = screen.getByTestId('manage-vega-wallet');
|
||||
expect(button).toHaveTextContent(truncateByChars(key.publicKey));
|
||||
expect(button).toHaveTextContent(key.name);
|
||||
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(await screen.findByRole('menu')).toBeInTheDocument();
|
||||
expect(await screen.findAllByRole('menuitemradio')).toHaveLength(
|
||||
keys.length
|
||||
const menuItems = await screen.findAllByRole('menuitemradio');
|
||||
expect(menuItems).toHaveLength(keys.length);
|
||||
|
||||
expect(within(menuItems[0]).getByTestId('alias')).toHaveTextContent(
|
||||
keyProfile.alias
|
||||
);
|
||||
|
||||
expect(within(menuItems[1]).getByTestId('alias')).toHaveTextContent(
|
||||
'No alias'
|
||||
);
|
||||
|
||||
expect(refreshKeys).toHaveBeenCalled();
|
||||
|
||||
fireEvent.click(screen.getByTestId(`key-${key2.publicKey}`));
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
TradingDropdownItem,
|
||||
TradingDropdownRadioItem,
|
||||
TradingDropdownItemIndicator,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { isBrowserWalletInstalled, type Key } from '@vegaprotocol/wallet';
|
||||
import { useDialogStore, useVegaWallet } from '@vegaprotocol/wallet-react';
|
||||
@ -22,6 +23,8 @@ import classNames from 'classnames';
|
||||
import { ViewType, useSidebar } from '../sidebar';
|
||||
import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { usePartyProfilesQuery } from './__generated__/PartyProfiles';
|
||||
import { useProfileDialogStore } from '../../stores/profile-dialog-store';
|
||||
|
||||
export const VegaWalletConnectButton = ({
|
||||
intent = Intent.None,
|
||||
@ -68,10 +71,10 @@ export const VegaWalletConnectButton = ({
|
||||
{activeKey ? (
|
||||
<>
|
||||
{activeKey && (
|
||||
<span className="uppercase">{activeKey.name}</span>
|
||||
<span className="uppercase">
|
||||
{activeKey.name ? activeKey.name : t('Unnamed key')}
|
||||
</span>
|
||||
)}
|
||||
{' | '}
|
||||
{truncateByChars(activeKey.publicKey)}
|
||||
</>
|
||||
) : (
|
||||
<>{'Select key'}</>
|
||||
@ -88,20 +91,11 @@ export const VegaWalletConnectButton = ({
|
||||
onEscapeKeyDown={() => setDropdownOpen(false)}
|
||||
>
|
||||
<div className="min-w-[340px]" data-testid="keypair-list">
|
||||
<TradingDropdownRadioGroup
|
||||
value={pubKey || undefined}
|
||||
onValueChange={(value) => {
|
||||
selectPubKey(value);
|
||||
}}
|
||||
>
|
||||
{pubKeys.map((pk) => (
|
||||
<KeypairItem
|
||||
key={pk.publicKey}
|
||||
pk={pk}
|
||||
active={pk.publicKey === pubKey}
|
||||
<KeypairRadioGroup
|
||||
pubKey={pubKey}
|
||||
pubKeys={pubKeys}
|
||||
onSelect={selectPubKey}
|
||||
/>
|
||||
))}
|
||||
</TradingDropdownRadioGroup>
|
||||
<TradingDropdownSeparator />
|
||||
{!isReadOnly && (
|
||||
<TradingDropdownItem
|
||||
@ -141,28 +135,52 @@ export const VegaWalletConnectButton = ({
|
||||
);
|
||||
};
|
||||
|
||||
const KeypairItem = ({ pk, active }: { pk: Key; active: boolean }) => {
|
||||
const KeypairRadioGroup = ({
|
||||
pubKey,
|
||||
pubKeys,
|
||||
onSelect,
|
||||
}: {
|
||||
pubKey: string | undefined;
|
||||
pubKeys: Key[];
|
||||
onSelect: (pubKey: string) => void;
|
||||
}) => {
|
||||
const { data } = usePartyProfilesQuery({
|
||||
variables: { partyIds: pubKeys.map((pk) => pk.publicKey) },
|
||||
skip: pubKeys.length <= 0,
|
||||
});
|
||||
|
||||
return (
|
||||
<TradingDropdownRadioGroup value={pubKey} onValueChange={onSelect}>
|
||||
{pubKeys.map((pk) => {
|
||||
const profile = data?.partiesProfilesConnection?.edges.find(
|
||||
(e) => e.node.partyId === pk.publicKey
|
||||
);
|
||||
return (
|
||||
<KeypairItem key={pk.publicKey} pk={pk} alias={profile?.node.alias} />
|
||||
);
|
||||
})}
|
||||
</TradingDropdownRadioGroup>
|
||||
);
|
||||
};
|
||||
|
||||
const KeypairItem = ({ pk, alias }: { pk: Key; alias: string | undefined }) => {
|
||||
const t = useT();
|
||||
const [copied, setCopied] = useCopyTimeout();
|
||||
const setOpen = useProfileDialogStore((store) => store.setOpen);
|
||||
|
||||
return (
|
||||
<TradingDropdownRadioItem value={pk.publicKey}>
|
||||
<div
|
||||
className={classNames('flex-1 mr-2', {
|
||||
'text-default': active,
|
||||
'text-muted': !active,
|
||||
})}
|
||||
data-testid={`key-${pk.publicKey}`}
|
||||
>
|
||||
<span className={classNames('mr-2 uppercase')}>
|
||||
{pk.name}
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{pk.name ? pk.name : t('Unnamed key')}</span>
|
||||
{' | '}
|
||||
{truncateByChars(pk.publicKey)}
|
||||
<span className="font-mono">
|
||||
{truncateByChars(pk.publicKey, 3, 3)}
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<CopyToClipboard text={pk.publicKey} onCopy={() => setCopied(true)}>
|
||||
<button
|
||||
data-testid="copy-vega-public-key"
|
||||
className="relative -top-px"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<span className="sr-only">{t('Copy')}</span>
|
||||
@ -170,7 +188,17 @@ const KeypairItem = ({ pk, active }: { pk: Key; active: boolean }) => {
|
||||
</button>
|
||||
</CopyToClipboard>
|
||||
{copied && <span className="text-xs">{t('Copied')}</span>}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={classNames('flex-1 mr-2 text-secondary text-sm')}
|
||||
data-testid={`key-${pk.publicKey}`}
|
||||
>
|
||||
<Tooltip description={t('Public facing key alias. Click to edit')}>
|
||||
<button data-testid="alias" onClick={() => setOpen(pk.publicKey)}>
|
||||
{alias ? alias : t('No alias')}
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<TradingDropdownItemIndicator />
|
||||
</TradingDropdownRadioItem>
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from '@vegaprotocol/web3';
|
||||
import { WelcomeDialog } from '../components/welcome-dialog';
|
||||
import { VegaWalletConnectDialog } from '../components/vega-wallet-connect-dialog';
|
||||
import { ProfileDialog } from '../components/profile-dialog';
|
||||
|
||||
const DialogsContainer = () => {
|
||||
const { isOpen, id, trigger, setOpen } = useAssetDetailsDialogStore();
|
||||
@ -24,6 +25,7 @@ const DialogsContainer = () => {
|
||||
<WelcomeDialog />
|
||||
<Web3ConnectUncontrolledDialog />
|
||||
<WithdrawalApprovalDialogContainer />
|
||||
<ProfileDialog />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
19
apps/trading/stores/profile-dialog-store.ts
Normal file
19
apps/trading/stores/profile-dialog-store.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface ProfileDialogStore {
|
||||
open: boolean;
|
||||
pubKey: string | undefined;
|
||||
setOpen: (pubKey: string | undefined) => void;
|
||||
}
|
||||
|
||||
export const useProfileDialogStore = create<ProfileDialogStore>((set) => ({
|
||||
open: false,
|
||||
pubKey: undefined,
|
||||
setOpen: (pubKey) => {
|
||||
if (pubKey) {
|
||||
set({ open: true, pubKey });
|
||||
} else {
|
||||
set({ open: false, pubKey: undefined });
|
||||
}
|
||||
},
|
||||
}));
|
@ -86,6 +86,7 @@
|
||||
"Docs": "Docs",
|
||||
"Earn commission & stake rewards": "Earn commission & stake rewards",
|
||||
"Earned by me": "Earned by me",
|
||||
"Edit alias": "Edit alias",
|
||||
"Eligible teams": "Eligible teams",
|
||||
"Enactment date reached and usual auction exit checks pass": "Enactment date reached and usual auction exit checks pass",
|
||||
"[empty]": "[empty]",
|
||||
@ -162,6 +163,7 @@
|
||||
"Joined": "Joined",
|
||||
"Joined at": "Joined at",
|
||||
"Joined epoch": "Joined epoch",
|
||||
"Key name": "Key name",
|
||||
"gameCount_one": "Last game result",
|
||||
"gameCount_other": "Last {{count}} game results",
|
||||
"Learn about providing liquidity": "Learn about providing liquidity",
|
||||
@ -194,6 +196,7 @@
|
||||
"My liquidity provision": "My liquidity provision",
|
||||
"My trading fees": "My trading fees",
|
||||
"Name": "Name",
|
||||
"No alias": "No alias",
|
||||
"No closed orders": "No closed orders",
|
||||
"No data": "No data",
|
||||
"No deposits": "No deposits",
|
||||
@ -227,6 +230,7 @@
|
||||
"Not connected": "Not connected",
|
||||
"Number of epochs after distribution to delay vesting of rewards by": "Number of epochs after distribution to delay vesting of rewards by",
|
||||
"Number of traders": "Number of traders",
|
||||
"On-change alias": "On-change alias",
|
||||
"Open": "Open",
|
||||
"Open a position": "Open a position",
|
||||
"Open markets": "Open markets",
|
||||
@ -249,6 +253,7 @@
|
||||
"Portfolio": "Portfolio",
|
||||
"Positions": "Positions",
|
||||
"Price": "Price",
|
||||
"Profile updated": "Profile updated",
|
||||
"Program ends:": "Program ends:",
|
||||
"Propose a new market": "Propose a new market",
|
||||
"Proposed final price is {{price}} {{assetSymbol}}.": "Proposed final price is {{price}} {{assetSymbol}}.",
|
||||
@ -289,6 +294,7 @@
|
||||
"Search": "Search",
|
||||
"See all markets": "See all markets",
|
||||
"Select market": "Select market",
|
||||
"Set party alias": "Set party alias",
|
||||
"Settings": "Settings",
|
||||
"Settlement asset": "Settlement asset",
|
||||
"Settlement date": "Settlement date",
|
||||
@ -311,6 +317,7 @@
|
||||
"Stop": "Stop",
|
||||
"Stop orders": "Stop orders",
|
||||
"Streak reward multiplier": "Streak reward multiplier",
|
||||
"Submit": "Submit",
|
||||
"Successor of a market": "Successor of a market",
|
||||
"Successors to this market have been proposed": "Successors to this market have been proposed",
|
||||
"Supplied stake": "Supplied stake",
|
||||
@ -371,6 +378,7 @@
|
||||
"Staking rewards": "Staking rewards",
|
||||
"Unknown": "Unknown",
|
||||
"Unknown settlement date": "Unknown settlement date",
|
||||
"Unnamed key": "Unnamed key",
|
||||
"Update team": "Update team",
|
||||
"URL": "URL",
|
||||
"Use a comma separated list to allow only specific public keys to join the team": "Use a comma separated list to allow only specific public keys to join the team",
|
||||
@ -407,8 +415,10 @@
|
||||
"You will no longer be able to hold a position on this market when it closes in {{duration}}.": "You will no longer be able to hold a position on this market when it closes in {{duration}}.",
|
||||
"Your code has been rejected": "Your code has been rejected",
|
||||
"Your identity is always anonymous on Vega": "Your identity is always anonymous on Vega",
|
||||
"Your key's private name, can be changed in your wallet": "Your key's private name, can be changed in your wallet",
|
||||
"Your referral code": "Your referral code",
|
||||
"Your tier": "Your tier",
|
||||
"Your public alias, stored on chain": "Your public alias, stored on chain",
|
||||
"checkOutProposalsAndVote": "Check out the terms of the proposals and vote:",
|
||||
"checkOutProposalsAndVote_one": "Check out the terms of the proposal and vote:",
|
||||
"checkOutProposalsAndVote_other": "Check out the terms of the proposals and vote:",
|
||||
|
@ -33,6 +33,12 @@ export const useSimpleTransaction = (opts?: Options) => {
|
||||
const [result, setResult] = useState<Result>();
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const reset = () => {
|
||||
setStatus('idle');
|
||||
setResult(undefined);
|
||||
setError(undefined);
|
||||
};
|
||||
|
||||
const send = async (tx: Transaction) => {
|
||||
if (!pubKey) {
|
||||
throw new Error('no pubKey');
|
||||
@ -114,5 +120,6 @@ export const useSimpleTransaction = (opts?: Options) => {
|
||||
error,
|
||||
status,
|
||||
send,
|
||||
reset,
|
||||
};
|
||||
};
|
||||
|
@ -492,6 +492,14 @@ export interface UpdateMarginMode {
|
||||
export interface UpdateMarginModeBody {
|
||||
updateMarginMode: UpdateMarginMode;
|
||||
}
|
||||
|
||||
export interface UpdatePartyProfile {
|
||||
updatePartyProfile: {
|
||||
alias: string;
|
||||
metadata: Array<{ key: string; value: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
export type Transaction =
|
||||
| UpdateMarginModeBody
|
||||
| StopOrdersSubmissionBody
|
||||
@ -510,7 +518,8 @@ export type Transaction =
|
||||
| ApplyReferralCode
|
||||
| JoinTeam
|
||||
| CreateReferralSet
|
||||
| UpdateReferralSet;
|
||||
| UpdateReferralSet
|
||||
| UpdatePartyProfile;
|
||||
|
||||
export interface TransactionResponse {
|
||||
transactionHash: string;
|
||||
|
Loading…
Reference in New Issue
Block a user