Skip to content

Commit 5705cdb

Browse files
committed
move general operations
1 parent 8e346aa commit 5705cdb

27 files changed

Lines changed: 1035 additions & 165 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
'use client';
2+
3+
import * as z from 'zod';
4+
import { useForm } from 'react-hook-form';
5+
import { zodResolver } from '@hookform/resolvers/zod';
6+
import { Form } from '@/components/ui/form';
7+
import { OperationsInputField } from '@/components/operations/operations-input-field';
8+
import { OperationsSubmitButton } from '@/components/operations/operations-submit-button';
9+
import {
10+
BytesValue,
11+
ContractCallPayloadBuilder,
12+
ContractFunction,
13+
TransactionPayload,
14+
TypedValue,
15+
} from '@multiversx/sdk-core';
16+
import { useAccount, useTransaction } from '@useelven/core';
17+
import { useTxStatus } from '@/hooks/use-tx-status';
18+
import { OperationInfoBox } from '@/components/operation-info-box';
19+
20+
const getKeyValuesForTx = (keyValuesArr: string[]) => {
21+
return keyValuesArr
22+
.map((keyValue: string) => {
23+
if (keyValue.includes(':')) {
24+
return keyValue
25+
.replaceAll(' ', '')
26+
.split(':')
27+
.map((val) => BytesValue.fromUTF8(val));
28+
}
29+
return [];
30+
})
31+
.flat();
32+
};
33+
34+
/**
35+
* @link https://docs.multiversx.com/developers/account-storage/#transaction-format
36+
* */
37+
const getTotalAdditionalGasLimit = (
38+
data: TransactionPayload,
39+
keyValuePairs: string[]
40+
) => {
41+
const saveKeyValueCost = 100_000;
42+
const moveBalanceCost = 50_000;
43+
const costPerByte = data.length() * 1_500;
44+
45+
let persistPerByteKey = 0;
46+
let persistPerByteValue = 0;
47+
let storePerByte = 0;
48+
49+
for (const keyValue of keyValuePairs) {
50+
if (keyValue.includes(':')) {
51+
const split = keyValue.replaceAll(' ', '').split(':');
52+
const key = split[0];
53+
const value = split[1];
54+
persistPerByteKey = persistPerByteKey + key.length * 1_000;
55+
persistPerByteValue = persistPerByteValue + value.length * 1_000;
56+
storePerByte = storePerByte + value.length * 10_000;
57+
}
58+
}
59+
60+
return (
61+
saveKeyValueCost +
62+
moveBalanceCost +
63+
costPerByte +
64+
persistPerByteKey +
65+
persistPerByteValue +
66+
storePerByte
67+
);
68+
};
69+
70+
const formSchema = z.object({
71+
keyValuePairs: z.string().min(1, 'The field is required'),
72+
});
73+
74+
export const AccountStorage = () => {
75+
const { address } = useAccount();
76+
77+
const { triggerTx, error, txResult, transaction, pending } = useTransaction();
78+
79+
const form = useForm<z.infer<typeof formSchema>>({
80+
resolver: zodResolver(formSchema),
81+
defaultValues: {
82+
keyValuePairs: '',
83+
},
84+
});
85+
86+
useTxStatus({
87+
successHash: txResult?.hash,
88+
pendingHash: transaction?.getHash()?.toString(),
89+
error,
90+
pending,
91+
});
92+
93+
const onSubmit = async ({ keyValuePairs }: z.infer<typeof formSchema>) => {
94+
const keyValuesArr = keyValuePairs.split(/\n/);
95+
const args: TypedValue[] = getKeyValuesForTx(keyValuesArr);
96+
97+
// TODO: use modern tools for contract calls
98+
const data = new ContractCallPayloadBuilder()
99+
.setFunction(new ContractFunction('SaveKeyValue'))
100+
.setArgs(args)
101+
.build();
102+
103+
triggerTx?.({
104+
address,
105+
gasLimit: getTotalAdditionalGasLimit(data, keyValuesArr),
106+
data,
107+
value: 0,
108+
});
109+
110+
form.reset();
111+
};
112+
113+
return (
114+
<>
115+
<OperationInfoBox error={error} txHash={txResult?.hash} />
116+
<Form {...form}>
117+
<form
118+
id="account-storage-form"
119+
onSubmit={form.handleSubmit(onSubmit)}
120+
className="space-y-8"
121+
>
122+
<div className="flex-1 overflow-auto p-1">
123+
<OperationsInputField
124+
name="keyValuePairs"
125+
label="Key value pairs"
126+
type="textarea"
127+
placeholder="Example: someKey:someValue"
128+
description="Please provide key-value data pairs. Each key-value pair should be separated with a new line. Keys can't begin with 'ELROND'."
129+
/>
130+
<OperationsSubmitButton />
131+
</div>
132+
</form>
133+
</Form>
134+
</>
135+
);
136+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { NextPage } from 'next';
2+
import { AccountStorage } from './components/account-storage';
3+
import { Separator } from '@/components/ui/separator';
4+
5+
const AccountStoragePage: NextPage = () => {
6+
return (
7+
<div>
8+
<div className="mb-6 flex flex-col">
9+
<h1 className="mb-3 scroll-m-20 text-2xl font-semibold leading-none tracking-tight">
10+
Account storage
11+
</h1>
12+
<p className="text-sm text-muted-foreground">
13+
The MultiversX protocol offers the possibility of storing additional
14+
data under an account as key-value pairs. This can be useful for many
15+
use cases. A wallet owner can store key-value pairs.
16+
</p>
17+
</div>
18+
<AccountStorage />
19+
<Separator className="my-12" />
20+
<div className="text-xs">
21+
<p className="mb-3">
22+
The MultiversX protocol enhances user experiences by allowing the
23+
storage of additional data as key-value pairs under an account. This
24+
feature is crucial for various applications, offering wallet owners a
25+
customizable way to manage data securely and efficiently within the
26+
blockchain.
27+
</p>
28+
<p className="mb-3">
29+
This capability is especially valuable for developers building
30+
decentralized applications (DApps) on the MultiversX platform,
31+
enabling more sophisticated functionalities. Users can store settings,
32+
preferences, or business logic, maintaining data integrity and
33+
security inherent to blockchain technology.
34+
</p>
35+
<p>
36+
In summary, MultiversX&apos;s key-value storage feature significantly
37+
improves the flexibility and functionality of DApps, positioning it as
38+
a robust tool for blockchain innovation.
39+
</p>
40+
</div>
41+
</div>
42+
);
43+
};
44+
45+
export default AccountStoragePage;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use client';
2+
3+
import * as z from 'zod';
4+
import { useForm } from 'react-hook-form';
5+
import {
6+
Address,
7+
AddressValue,
8+
ContractCallPayloadBuilder,
9+
ContractFunction,
10+
TypedValue,
11+
} from '@multiversx/sdk-core';
12+
import { zodResolver } from '@hookform/resolvers/zod';
13+
import { Form } from '@/components/ui/form';
14+
import { OperationsInputField } from '@/components/operations/operations-input-field';
15+
import { OperationsSubmitButton } from '@/components/operations/operations-submit-button';
16+
import { commonBuiltInOpertationsGasLimit } from '@/components/operations/constants';
17+
import { useTxStatus } from '@/hooks/use-tx-status';
18+
import { useTransaction } from '@useelven/core';
19+
import { OperationInfoBox } from '@/components/operation-info-box';
20+
21+
const formSchema = z.object({
22+
smartContractAddress: z.string().min(1, 'The field is required'),
23+
newOwnerAddress: z.string().min(1, 'The field is required'),
24+
});
25+
26+
export const ChangeOwnerAddress = () => {
27+
const { triggerTx, error, txResult, transaction, pending } = useTransaction();
28+
29+
const form = useForm<z.infer<typeof formSchema>>({
30+
resolver: zodResolver(formSchema),
31+
defaultValues: {
32+
smartContractAddress: '',
33+
newOwnerAddress: '',
34+
},
35+
});
36+
37+
useTxStatus({
38+
successHash: txResult?.hash,
39+
pendingHash: transaction?.getHash()?.toString(),
40+
error,
41+
pending,
42+
});
43+
44+
const onSubmit = async ({
45+
smartContractAddress,
46+
newOwnerAddress,
47+
}: z.infer<typeof formSchema>) => {
48+
const args: TypedValue[] = [
49+
new AddressValue(new Address(newOwnerAddress.trim())),
50+
];
51+
52+
// TODO: use modern tools for contract calls
53+
const data = new ContractCallPayloadBuilder()
54+
.setFunction(new ContractFunction('ChangeOwnerAddress'))
55+
.setArgs(args)
56+
.build();
57+
58+
triggerTx?.({
59+
address: smartContractAddress.trim(),
60+
gasLimit: commonBuiltInOpertationsGasLimit,
61+
data,
62+
value: 0,
63+
});
64+
65+
form.reset();
66+
};
67+
68+
return (
69+
<>
70+
<OperationInfoBox error={error} txHash={txResult?.hash} />
71+
<Form {...form}>
72+
<form
73+
id="change-owner-form"
74+
onSubmit={form.handleSubmit(onSubmit)}
75+
className="space-y-8"
76+
>
77+
<div className="flex-1 overflow-auto p-1">
78+
<OperationsInputField
79+
name="smartContractAddress"
80+
label="Smart contract address"
81+
placeholder="Example: erd1qqqqqqq..."
82+
description="Please provide the address of the smart contract"
83+
/>
84+
<OperationsInputField
85+
name="newOwnerAddress"
86+
label="New owner address"
87+
placeholder="Example: erd1..."
88+
description="Please provide the address of the new owner of the smart contract"
89+
/>
90+
</div>
91+
<OperationsSubmitButton />
92+
</form>
93+
</Form>
94+
</>
95+
);
96+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { NextPage } from 'next';
2+
import { ChangeOwnerAddress } from './components/change-owner-address';
3+
import { Separator } from '@/components/ui/separator';
4+
5+
const ChangeOwnerAddressPage: NextPage = () => {
6+
return (
7+
<div>
8+
<div className="mb-6 flex flex-col">
9+
<h1 className="mb-3 scroll-m-20 text-2xl font-semibold leading-none tracking-tight">
10+
Change owner address
11+
</h1>
12+
<p className="text-sm text-muted-foreground">
13+
Change owner address is an operation to be made by a Smart
14+
Contract&apos;s owner when a new owner is desired.
15+
</p>
16+
</div>
17+
<ChangeOwnerAddress />
18+
<Separator className="my-12" />
19+
<div className="text-xs">
20+
<p className="mb-3">
21+
The ChangeOwnerAddress functionality is specifically designed for use
22+
by current owners of a Smart Contract who wish to transfer ownership
23+
to a new party. This function is an essential tool for managing the
24+
control and administration of the Smart Contract, allowing for
25+
seamless transitions between owners which is crucial for maintaining
26+
the integrity and continuous operation of the contract.
27+
</p>
28+
<p>
29+
When a Smart Contract owner decides to designate a new owner,
30+
activating this function facilitates the necessary update in ownership
31+
records. This capability ensures that the Smart Contract remains under
32+
responsible stewardship at all times, enabling effective and secure
33+
management of the contract&apos;s functionalities and associated
34+
assets.
35+
</p>
36+
</div>
37+
</div>
38+
);
39+
};
40+
41+
export default ChangeOwnerAddressPage;

0 commit comments

Comments
 (0)