Skip to content

Commit e8e02e9

Browse files
committed
move fungible tokens operations in progress
1 parent 5462c0f commit e8e02e9

19 files changed

Lines changed: 797 additions & 119 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
'use client';
2+
3+
import * as z from 'zod';
4+
import { useForm, useWatch } from 'react-hook-form';
5+
import { zodResolver } from '@hookform/resolvers/zod';
6+
import { Form } from '@/components/ui/form';
7+
import {
8+
esdtTokenSpecialRoles,
9+
nftTokenSpecialRoles,
10+
sftTokenSpecialRoles,
11+
commonOpertationsGasLimit,
12+
builtInSC,
13+
TokenPropertyOrRole,
14+
} from '@/components/operations/constants';
15+
import { OperationsInputField } from '@/components/operations/operations-input-field';
16+
import { OperationsCheckboxGroup } from '@/components/operations/operations-checkbox-group';
17+
import { OperationsSubmitButton } from '@/components/operations/operations-submit-button';
18+
import { useEffect, useState } from 'react';
19+
import { CommonOpertationContentProps } from '@/components/operations/operations-common-types';
20+
import { OperationsRadioGroup } from '@/components/operations/operations-radio-group';
21+
import { useAccount, useTransaction } from '@useelven/core';
22+
import { useTokenRolesByAccount } from '@/hooks/use-token-roles-by-account';
23+
import { OperationsTokenIdInput } from '@/components/operations/operations-tokenid-input';
24+
import { OperationInfoBox } from '@/components/operation-info-box';
25+
import { useTxStatus } from '@/hooks/use-tx-status';
26+
27+
const formSchema = z.object({
28+
tokenId: z.string().min(1, 'The field is required'),
29+
address: z.string().min(1, 'The field is required'),
30+
roles: z.array(z.string()),
31+
type: z.enum(['set', 'unset'], {
32+
required_error: 'Please choose the type of the operation (set/unset)',
33+
}),
34+
});
35+
36+
const rolesMap: Record<
37+
CommonOpertationContentProps['tokenType'],
38+
TokenPropertyOrRole[]
39+
> = {
40+
fungible: esdtTokenSpecialRoles,
41+
'non-fungible': nftTokenSpecialRoles,
42+
'semi-fungible': sftTokenSpecialRoles,
43+
meta: sftTokenSpecialRoles,
44+
};
45+
46+
export const ToggleSpecialRoles = ({
47+
tokenType,
48+
}: {
49+
tokenType: CommonOpertationContentProps['tokenType'];
50+
}) => {
51+
const { triggerTx, error, txResult, transaction, pending } = useTransaction();
52+
53+
const { address } = useAccount();
54+
const [disabledRoles, setDisabledRoles] = useState<string[]>();
55+
56+
const form = useForm<z.infer<typeof formSchema>>({
57+
resolver: zodResolver(formSchema),
58+
defaultValues: {
59+
tokenId: '',
60+
address,
61+
type: 'set',
62+
roles: [],
63+
},
64+
});
65+
66+
const watchTokenId = useWatch({ name: 'tokenId', control: form.control });
67+
const watchAddress = useWatch({ name: 'address', control: form.control });
68+
const watchType = useWatch({ name: 'type', control: form.control });
69+
70+
const { roles } = useTokenRolesByAccount({
71+
tokenId: watchTokenId,
72+
tokenType,
73+
address: watchAddress,
74+
});
75+
76+
useTxStatus({
77+
successHash: txResult?.hash,
78+
pendingHash: transaction?.getHash()?.toString(),
79+
error,
80+
pending,
81+
});
82+
83+
// Handle selected roles in form
84+
useEffect(() => {
85+
const roleNames = rolesMap[tokenType].map((role) => role.name);
86+
87+
if (!watchTokenId || !watchAddress) {
88+
setDisabledRoles(roleNames);
89+
return;
90+
}
91+
92+
let disabledRoles: string[] = [];
93+
if (watchType === 'set') {
94+
disabledRoles = roles;
95+
} else {
96+
disabledRoles = roleNames.filter((role) => !roles?.includes(role));
97+
}
98+
setDisabledRoles(disabledRoles);
99+
// eslint-disable-next-line react-hooks/exhaustive-deps
100+
}, [roles, watchType, watchTokenId, watchAddress]);
101+
102+
const onSubmit = async ({
103+
tokenId,
104+
address,
105+
roles,
106+
type,
107+
}: z.infer<typeof formSchema>) => {
108+
const {
109+
BytesValue,
110+
AddressValue,
111+
Address,
112+
ContractCallPayloadBuilder,
113+
ContractFunction,
114+
} = await import('@multiversx/sdk-core');
115+
116+
const args = [
117+
BytesValue.fromUTF8(tokenId.trim()),
118+
new AddressValue(new Address(address.trim())),
119+
];
120+
121+
for (const role of rolesMap[tokenType]) {
122+
if (roles.includes(role.name)) {
123+
args.push(BytesValue.fromUTF8(role.name));
124+
}
125+
}
126+
127+
const data = new ContractCallPayloadBuilder()
128+
.setFunction(
129+
new ContractFunction(
130+
type === 'set' ? 'setSpecialRole' : 'unSetSpecialRole'
131+
)
132+
)
133+
.setArgs(args)
134+
.build();
135+
136+
triggerTx?.({
137+
address: builtInSC.trim(),
138+
gasLimit: commonOpertationsGasLimit,
139+
data,
140+
value: 0,
141+
});
142+
143+
form.reset();
144+
};
145+
146+
const rolesDescription = () => {
147+
if (!watchAddress || !watchTokenId) {
148+
return 'Please set tokenId and address, then you can choose roles!';
149+
}
150+
return `Disabled ones are ${
151+
form.getValues('type') === 'set'
152+
? "set, so you can't set them"
153+
: "not set, so you can't unset them"
154+
}.`;
155+
};
156+
157+
return (
158+
<>
159+
<OperationInfoBox error={error} txHash={txResult?.hash} />
160+
<Form {...form}>
161+
<form
162+
id="toggle-special-roles-form"
163+
onSubmit={form.handleSubmit(onSubmit)}
164+
className="space-y-8"
165+
>
166+
<div className="flex-1 overflow-auto p-1">
167+
<OperationsRadioGroup
168+
items={[
169+
{ name: 'set', description: 'Set roles' },
170+
{ name: 'unset', description: 'Unset roles' },
171+
]}
172+
name="type"
173+
label="Operation type"
174+
description="Please choose the type of the operation. Set or Unset."
175+
/>
176+
<OperationsTokenIdInput tokenType={tokenType} />
177+
<OperationsInputField
178+
name="address"
179+
label="Address"
180+
placeholder="Example: erd1..."
181+
description="Please provide the address for which the roles will be assigned. By default your own."
182+
/>
183+
<OperationsCheckboxGroup
184+
items={rolesMap[tokenType]}
185+
disabledItems={disabledRoles}
186+
name="roles"
187+
label="Roles"
188+
description={`Special roles available for basic ESDT tokens. ${rolesDescription()}`}
189+
/>
190+
</div>
191+
<OperationsSubmitButton formId="toggle-special-roles-form" />
192+
</form>
193+
</Form>
194+
</>
195+
);
196+
};

0 commit comments

Comments
 (0)