Skip to content

Commit

Permalink
improve sc queries and updates
Browse files Browse the repository at this point in the history
  • Loading branch information
juliancwirko committed Jan 28, 2023
1 parent 92a1f74 commit ac71669
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ NEXT_PUBLIC_MULTIVERSX_CHAIN = devnet
NEXT_PUBLIC_DAPP_HOST = http://localhost:3000

# The Elven Tools NFT minter smart contract
NEXT_PUBLIC_NFT_SMART_CONTRACT = erd1qqqqqqqqqqqqqpgq5za2pty2tlfqhj20z9qmrrpjmyt6advcgtkscm7xep
NEXT_PUBLIC_NFT_SMART_CONTRACT = erd1qqqqqqqqqqqqqpgqztp5vpqrxe2tha224jwsa3sv2800a88zgtksar2kc8

# The name for the mint endpoint (change it if you have change it in the smart contract)
NEXT_PUBLIC_MINT_FUNCTION_NAME = 'mint'
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### [4.2.0](https://github.com/ElvenTools/elven-tools-dapp/releases/tag/v4.2.0) (2023-01-28)
- rebuilt in-app navigation using Next Link instead ActionButton that should be used only for triggering functions, and not navigation
- `useScQuery` can now query more complex data using abi file
- `useScQuery` can now query more complex data using abi file and result parser from MultiversX sdk-core
- better errors handling through the network provider
- update npm dependencies

Expand Down
41 changes: 37 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### Elven Tools Dapp

- Docs: [elven.tools/docs/minter-dapp-introduction.html](https://www.elven.tools/docs/minter-dapp-introduction.html)
- Dapp's React hooks and components [elven.tools/docs/dapp-react-hooks-and-components.html](https://www.elven.tools/docs/dapp-react-hooks-and-components.html)
- Demo: [dapp-demo.elven.tools](https://dapp-demo.elven.tools)
- Elven Tools intro (including the Dapp): [youtu.be/Jou5jn8PFz8](https://youtu.be/Jou5jn8PFz8)

Expand Down Expand Up @@ -32,7 +33,7 @@ const { login, isLoggedIn, error, walletConnectUri, getHWAccounts } = useLogin()
login(LoginMethodsEnum.ledger)
```

Custom mint transactions for the Elven Tools Smart Contract. There is also a more generic `useScTransaction`` hook.
Custom mint transactions for the Elven Tools Smart Contract. There is also a more generic `useScTransaction` hook.

```jsx
const { mint, pending, transaction, error } = useMintTransaction();
Expand All @@ -42,7 +43,7 @@ const { mint, pending, transaction, error } = useMintTransaction();
mint(amount)
```

Query the Elven Tools Smart Contract. There is also a more generic `useScQuery`` hook.
Query the Elven Tools Smart Contract. There is also a more generic `useScQuery` hook.

```jsx
const {
Expand All @@ -60,6 +61,38 @@ const {
fetch()
```

You can also query more complex data types. Then you will need to provide the ABI JSON file.

```jsx
import { TypedOutcomeBundle } from '@multiversx/sdk-core';
import abiJSON from '../config/abi.json';

const { data } = useScQuery<TypedOutcomeBundle>({
type: SCQueryType.COMPLEX,
payload: {
scAddress: 'erd1qqq...',
funcName: 'yourScFunction',
args: [], // args in hex format, use erdjs for conversion, see above
},
autoInit: true,
abiJSON,
});
```

The `data` here will be a `TypedOutcomeBundle`. Which is:

```typescript
interface TypedOutcomeBundle {
returnCode: ReturnCode;
returnMessage: string;
values: TypedValue[];
firstValue?: TypedValue;
secondValue?: TypedValue;
thirdValue?: TypedValue;
lastValue?: TypedValue;
}
```

For more docs on how to use it check the link above, and for more examples see: [elven.tools/docs/dapp-react-hooks-and-components.html](https://elven.tools/docs/dapp-react-hooks-and-components.html)

### Tracking the progress
Expand Down Expand Up @@ -87,9 +120,9 @@ Check detailed docs on it here: [How to start with the Dapp](https://www.elven.t

- it works on Nextjs
- it uses the newest version of [sdk-core](https://github.com/multiversx/mx-sdk-js-core) without the [sdk-dapp](https://github.com/multiversx/mx-sdk-dapp) library.
it uses backend-side rewrites to hide the API endpoint. The only exposed one is `/api`
- optionally it uses backend-side rewrites to hide the API endpoint, then the only exposed one is `/api`
- it uses .env file - there is an example in the repo
- it uses chakra-ui
- it uses [chakra-ui](https://chakra-ui.com/)

More docs on it: [Minter Dapp introduction](https://www.elven.tools/docs/minter-dapp-introduction.html)

Expand Down
2 changes: 2 additions & 0 deletions components/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// The component for triggering functions. For in-app navigation use Next Link component

import { Box, BoxProps } from '@chakra-ui/react';
import { FC, PropsWithChildren, useCallback } from 'react';

Expand Down
2 changes: 1 addition & 1 deletion config/dappUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const roadmap = [
{
title: 'Q1 2023',
points: [
'UI automated tests',
'MultiversX rebranding and dependecies replacement',
'Nextjs configuration improvements',
'Better UI and more functionality',
],
Expand Down
9 changes: 8 additions & 1 deletion hooks/interaction/elvenScHooks/useElvenScQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ interface ScConfigDataArgs {
type: SCQueryType;
args?: string[];
autoInit?: boolean;
abiJSON?: {
name: string;
endpoints: unknown[];
types: unknown;
};
}

export function useElvenScQuery<T extends string | number | boolean>({
export function useElvenScQuery<T extends string | number | boolean | unknown>({
funcName,
type,
args = [],
autoInit = true,
abiJSON,
}: ScConfigDataArgs) {
const { data, isLoading, fetch } = useScQuery<T>({
type,
Expand All @@ -27,6 +33,7 @@ export function useElvenScQuery<T extends string | number | boolean>({
args,
},
autoInit,
abiJSON,
});

return {
Expand Down
55 changes: 53 additions & 2 deletions hooks/interaction/useScQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,34 @@
// There is also useElvenScQuery which is specific to the Elven Tools smart contract and uses this hook under the hood

import useSWR, { Fetcher } from 'swr';
import {
ResultsParser,
SmartContractAbi,
SmartContract,
Address,
AbiRegistry,
} from '@multiversx/sdk-core';
import { ContractQueryResponse } from '@multiversx/sdk-network-providers';
import useSwrMutation from 'swr/mutation';
import { apiCall } from '../../utils/apiCall';

export enum SCQueryType {
NUMBER = 'number',
STRING = 'string',
BOOLEAN = 'boolean',
COMPLEX = 'complex',
}

interface SCQueryData {
type: SCQueryType;
payload?: Record<string, unknown>;
options?: Record<string, unknown>;
autoInit?: boolean;
abiJSON?: {
name: string;
endpoints: unknown[];
types: unknown;
};
}

interface FetcherArgs {
Expand All @@ -34,11 +48,12 @@ export const fetcher: Fetcher<VMOutput, FetcherArgs> = async ({
payload,
}) => await apiCall.post(url, payload || {});

export function useScQuery<T extends number | string | boolean>({
export function useScQuery<T extends number | string | boolean | unknown>({
type,
payload,
options,
autoInit = true,
abiJSON,
}: SCQueryData) {
let url = '';

Expand All @@ -52,6 +67,10 @@ export function useScQuery<T extends number | string | boolean>({
case SCQueryType.BOOLEAN:
url = '/vm-values/int';
break;
// You need to provide ABI JSON for proper results parsing
case SCQueryType.COMPLEX:
url = '/vm-values/query';
break;
}

const { data, error, mutate, isValidating, isLoading } = useSWR(
Expand All @@ -75,10 +94,42 @@ export function useScQuery<T extends number | string | boolean>({
revalidate: true,
});

const parseData = (data: string | number | undefined) => {
const parseData = (data: string | number | undefined | unknown) => {
if (type === SCQueryType.COMPLEX && !abiJSON) {
throw new Error(
'Please provide the ABI JSON contents if you want to use the COMPLEX queries in useScQuery! Check README.md for more info.'
);
}

if (
type === SCQueryType.COMPLEX &&
abiJSON &&
(data as Record<string, unknown>)?.returnData &&
payload?.scAddress &&
payload?.funcName
) {
const parser = new ResultsParser();
const abiRegistry = AbiRegistry.create(abiJSON);
const abi = new SmartContractAbi(abiRegistry, [abiJSON.name]);
const contract = new SmartContract({
address: new Address(payload.scAddress as string),
abi: abi,
});
const endpointDefinition = contract.getEndpoint(
payload.funcName as string
);
const smResponse = ContractQueryResponse.fromHttpResponse(data);
const parsedResponse = parser.parseQueryResponse(
smResponse,
endpointDefinition
);
return parsedResponse;
}

if (type === SCQueryType.BOOLEAN) {
return Boolean(Number(data));
}

if (type === SCQueryType.NUMBER) {
return Number(data);
}
Expand Down

0 comments on commit ac71669

Please sign in to comment.