Skip to content

Commit a2be651

Browse files
committed
Improve user informations
1 parent 99b8797 commit a2be651

File tree

3 files changed

+120
-44
lines changed

3 files changed

+120
-44
lines changed

frontend/src/components/MNSClaim.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
11
import { Button, toast } from '@massalabs/react-ui-kit';
22
import { InputWithRightText } from './InputWithRightText';
33
import { useState } from 'react';
4-
import { useWriteMNS } from '../utils/write-mns-sc';
4+
import { DnsGetAllocCostResponse, useWriteMNS } from '../utils/write-mns-sc';
55
import { useAccountStore } from '../lib/connectMassaWallets/store';
66
import { toMAS } from '@massalabs/massa-web3';
77

88
export function MNSClaim() {
99
const [domain, setDomain] = useState<string>('');
1010
const { connectedAccount, massaClient } = useAccountStore();
1111
const { dnsAlloc, getAllocCost } = useWriteMNS(massaClient);
12-
const [price, setPrice] = useState<bigint>(0n);
12+
const [allocCost, setAllocCost] = useState<DnsGetAllocCostResponse>({price: 0n});
1313

1414
function claim() {
1515
if (!connectedAccount) {
1616
toast.error('Please connect your wallet');
1717
return;
1818
}
19+
if (!allocCost.price) {
20+
toast.error('Invalid price');
21+
return;
22+
}
1923
dnsAlloc({
2024
domain,
2125
targetAddress: connectedAccount.address(),
22-
coins: price,
26+
coins: allocCost.price,
2327
});
2428
}
2529

@@ -28,12 +32,16 @@ export function MNSClaim() {
2832
toast.error('Please connect your wallet');
2933
return;
3034
}
35+
if (domain == '') {
36+
setAllocCost({price: 0n});
37+
return;
38+
}
3139
setDomain(domain);
3240
getAllocCost({
3341
domain,
3442
targetAddress: connectedAccount?.address() ?? '',
3543
}).then((cost) => {
36-
setPrice(cost);
44+
setAllocCost(cost);
3745
});
3846
}
3947
return (
@@ -48,11 +56,19 @@ export function MNSClaim() {
4856
onDomainChange(e.target.value);
4957
}}
5058
/>
51-
<p className="mb-4 font-light text-neutral">
52-
Price {toMAS(price).toFixed(4)} MAS
53-
</p>
59+
{
60+
allocCost.price !== null ? (
61+
<p className="mb-4 font-light text-neutral">
62+
Price {toMAS(allocCost.price).toFixed(4)} MAS
63+
</p>
64+
) : (
65+
<p className="mb-4 font-light text-s-error">
66+
{allocCost.error}
67+
</p>
68+
)
69+
}
5470
</div>
55-
<Button onClick={() => claim()}>Claim</Button>
71+
<Button disabled={allocCost.price !== null ? false : true} onClick={() => claim()}>Claim</Button>
5672
</div>
5773
</div>
5874
);

frontend/src/components/MNSList.tsx

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,43 +14,28 @@ import {
1414
Tooltip,
1515
} from '@massalabs/react-ui-kit';
1616
import { useAccountStore } from '../lib/connectMassaWallets/store';
17-
import { useCallback, useEffect, useState } from 'react';
18-
import { DnsUserEntryListResult, useWriteMNS } from '../utils/write-mns-sc';
17+
import { useEffect, useState } from 'react';
18+
import { useWriteMNS } from '../utils/write-mns-sc';
1919

2020
export function MNSList() {
21-
const { massaClient, connectedAccount } = useAccountStore();
22-
const { getUserEntryList, deleteDnsEntry, changeTargetAddressDnsEntry } =
21+
const { connectedAccount, massaClient } = useAccountStore();
22+
const { getUserEntryList, deleteDnsEntry, changeTargetAddressDnsEntry, list, listSpinning } =
2323
useWriteMNS(massaClient);
24-
const [spinning, setSpinning] = useState(false);
25-
const [list, setList] = useState<DnsUserEntryListResult[]>([]);
2624

25+
console.log('listSpinning in list', listSpinning);
2726
const [changeTargetModalId, setChangeTargetModalId] = useState<string | null>(
2827
null,
2928
);
3029
const [newTargetAddress, setNewTargetAddress] = useState<string>('');
31-
32-
const updateDnsEntryList = useCallback(async () => {
33-
if (connectedAccount && massaClient && !spinning && !list.length) {
34-
setSpinning(true);
35-
getUserEntryList({ address: connectedAccount.address() })
36-
.then((entries) => {
37-
setList(entries);
38-
setSpinning(false);
39-
})
40-
.catch(() => {
41-
setSpinning(false);
42-
});
43-
}
44-
}, [massaClient, connectedAccount, spinning, getUserEntryList]);
45-
30+
4631
useEffect(() => {
47-
updateDnsEntryList();
48-
}, [massaClient, updateDnsEntryList]);
49-
32+
if (!connectedAccount || !massaClient || listSpinning) return;
33+
getUserEntryList({address: connectedAccount.address() })
34+
}, [connectedAccount, massaClient]);
5035
return (
5136
<div>
52-
<Accordion customClass="border-none" title="Entry list">
53-
{spinning ? (
37+
<Accordion customClass="border-none" title="Owned MNS">
38+
{listSpinning ? (
5439
<div className="flex items-center justify-center">
5540
<Spinner />
5641
</div>
@@ -97,12 +82,12 @@ export function MNSList() {
9782
<div key={idx} className="bg-secondary rounded-xl p-4 mb-4">
9883
<div className="flex flex-row">
9984
<div className="flex justify-between grow">
100-
<p className="mas-body my-auto">
85+
<p className="mas-body my-auto w-32">
10186
{item.domain + '.massa'}
10287
</p>
10388
<ChevronDoubleRightIcon className="w-6" />
10489
<Tooltip body={item.targetAddress}>
105-
<p className="mas-body pr-4 my-auto ">
90+
<p className="mas-body pr-4 my-auto w-28 ">
10691
{item.targetAddress.slice(0, 10)}...
10792
</p>
10893
</Tooltip>
@@ -113,17 +98,19 @@ export function MNSList() {
11398
setChangeTargetModalId(item.domain);
11499
}}
115100
>
116-
<PencilIcon className="w-5 mr-2 my-auto" />
117-
<p className="mas-body mr-4 my-auto">Change target</p>
101+
<Tooltip body={<p className="mas-body">Change target</p>}>
102+
<PencilIcon className="w-4 pt-1" />
103+
</Tooltip>
118104
</button>
119105
<button
120106
className="flex"
121107
onClick={() => {
122108
deleteDnsEntry({ tokenId: item.tokenId });
123109
}}
124110
>
125-
<TrashIcon className="w-5 mr-2 my-auto" />
126-
<p className="mas-body my-auto">Delete</p>
111+
<Tooltip body={<p className="mas-body">Delete</p>}>
112+
<TrashIcon className="w-4 mr-2 pt-1" />
113+
</Tooltip>
127114
</button>
128115
</div>
129116
</div>

frontend/src/utils/write-mns-sc.tsx

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
bytesToStr,
99
bytesToU256,
1010
bytesToU64,
11+
toMAS,
1112
u256ToBytes,
1213
} from '@massalabs/massa-web3';
1314
import { ToastContent, toast } from '@massalabs/react-ui-kit';
@@ -49,6 +50,11 @@ export interface DnsUserEntryListResult {
4950
tokenId: bigint;
5051
}
5152

53+
export interface DnsGetAllocCostResponse {
54+
price: bigint | null;
55+
error?: string;
56+
}
57+
5258
type callSmartContractOptions = {
5359
coins?: bigint;
5460
fee?: bigint;
@@ -63,8 +69,11 @@ export function useWriteMNS(client?: Client) {
6369
const [isSuccess, setIsSuccess] = useState(false);
6470
const [isError, setIsError] = useState(false);
6571
const [opId, setOpId] = useState<string | undefined>(undefined);
72+
const [list, setList] = useState<DnsUserEntryListResult[]>([]);
73+
const [listSpinning, setListSpinning] = useState(false);
6674

67-
async function getAllocCost(params: DnsAllocParams): Promise<bigint> {
75+
async function getAllocCost(params: DnsAllocParams): Promise<DnsGetAllocCostResponse> {
76+
let price = 0n
6877
try {
6978
let args = new Args();
7079
args.addString(params.domain);
@@ -75,12 +84,63 @@ export function useWriteMNS(client?: Client) {
7584
parameter: args.serialize(),
7685
});
7786
if (!response) {
78-
return 0n;
87+
return {
88+
price: null,
89+
error: 'Failed to get alloc cost',
90+
};
7991
}
80-
return bytesToU64(response.returnValue);
92+
price = bytesToU64(response.returnValue);
93+
} catch (error) {
94+
return {
95+
price: null,
96+
error: 'Invalid domain name. Name can only be 2-100 characters long and can contains only lowercase letters, numbers and hyphens.',
97+
};
98+
}
99+
try {
100+
let args = new Args();
101+
args.addString(params.domain);
102+
let result = await client?.smartContracts().readSmartContract({
103+
targetAddress: SC_ADDRESS,
104+
targetFunction: 'dnsResolve',
105+
parameter: args.serialize(),
106+
});
107+
if (!result) {
108+
return {
109+
price: null,
110+
error: 'Failed to get alloc cost',
111+
};
112+
}
113+
return {
114+
price: null,
115+
error: `Domain already claimed by ${bytesToStr(result.returnValue)}`,
116+
}
81117
} catch (error) {
82-
return 0n;
83118
}
119+
try {
120+
let resultBalance = await client?.publicApi().getAddresses([params.targetAddress]);
121+
if (!resultBalance) {
122+
return {
123+
price: null,
124+
error: 'Failed to get alloc cost',
125+
};
126+
}
127+
let balance = BigInt((parseFloat(resultBalance[0].candidate_balance) * 1_000_000_000).toFixed(0));
128+
if (balance < price) {
129+
return {
130+
price: null,
131+
error: `The price of the domain is ${toMAS(price).toFixed(4)} MAS. Your balance is ${toMAS(balance).toFixed(4)} MAS. Please top up your account.`
132+
}
133+
}
134+
} catch (error) {
135+
console.log(error)
136+
return {
137+
price: null,
138+
error: 'Your account does not exist in the Massa network. Please transfer 0.1 MAS to your account to create it on chain.',
139+
};
140+
}
141+
return {
142+
price: price,
143+
};
84144
}
85145

86146
function callSmartContract(
@@ -158,6 +218,7 @@ export function useWriteMNS(client?: Client) {
158218
setIsSuccess(true);
159219
setIsPending(false);
160220
toast.dismiss(toastId);
221+
getUserEntryList({address: client.wallet().getBaseAccount()?.address()!})
161222
toast.success((t) => (
162223
<ToastContent t={t}>
163224
<OperationToast
@@ -230,13 +291,15 @@ export function useWriteMNS(client?: Client) {
230291
async function getUserEntryList(
231292
params: DnsUserEntryListParams,
232293
): Promise<DnsUserEntryListResult[]> {
294+
setListSpinning(true);
233295
let resultBalance = await client?.smartContracts().readSmartContract({
234296
targetAddress: SC_ADDRESS,
235297
targetFunction: 'balanceOf',
236298
parameter: new Args().addString(params.address).serialize(),
237299
});
238300
if (!resultBalance) {
239301
toast.error('Failed to get user entry list', { duration: 5000 });
302+
setListSpinning(false);
240303
return [];
241304
}
242305
let balance = bytesToU256(resultBalance.returnValue);
@@ -255,13 +318,15 @@ export function useWriteMNS(client?: Client) {
255318
let results = await client?.publicApi().getDatastoreEntries(listAsked);
256319
if (!results) {
257320
toast.error('Failed to get user entry list', { duration: 5000 });
321+
setListSpinning(false);
258322
return [];
259323
}
260324
for (let j = 0; j < results.length; j++) {
261325
let entry = results[j].candidate_value;
262326
if (!entry || entry.length == 0) {
263327
continue;
264328
}
329+
console.log(entry, addressBytes);
265330
if (compareUint8Array(entry, addressBytes)) {
266331
let tokenId = i + BigInt(j);
267332
let resultDomain = await client?.smartContracts().readSmartContract({
@@ -271,6 +336,7 @@ export function useWriteMNS(client?: Client) {
271336
});
272337
if (!resultDomain) {
273338
toast.error('Failed to get user entry list', { duration: 5000 });
339+
setListSpinning(false);
274340
return [];
275341
}
276342
const domain = bytesToStr(resultDomain.returnValue);
@@ -281,6 +347,7 @@ export function useWriteMNS(client?: Client) {
281347
});
282348
if (!targetAddress) {
283349
toast.error('Failed to get user entry list', { duration: 5000 });
350+
setListSpinning(false);
284351
return [];
285352
}
286353
list.push({
@@ -296,8 +363,12 @@ export function useWriteMNS(client?: Client) {
296363
// Rate limiting
297364
await sleep(1000);
298365
}
366+
setList(list);
367+
setListSpinning(false);
299368
return list;
300369
}
370+
console.log('listSpinning in hook', listSpinning);
371+
301372
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
302373

303374
function compareUint8Array(a: Uint8Array, b: Uint8Array) {
@@ -348,6 +419,8 @@ export function useWriteMNS(client?: Client) {
348419
isPending,
349420
isSuccess,
350421
isError,
422+
list,
423+
listSpinning,
351424
dnsAlloc,
352425
getAllocCost,
353426
getUserEntryList,

0 commit comments

Comments
 (0)