xdevguild / nextjs-dapp-template

Open source Next.js app template for the MultiversX blockchain. Including Shadcn UI and Tailwind.
https://multiversx-nextjs-dapp.netlify.app
MIT License
47 stars 16 forks source link

Support for calling smart contract endpoints, which expect MultiESDT payment #5

Closed Alannek1992 closed 2 years ago

Alannek1992 commented 2 years ago

Hi @juliancwirko,

First of all thank you for this extra ordinary work. This lightweight template is very impressive.

I would like to ask whether it has also support for calling smart contract endpoints, which expect MultiESDT payment.

Thanks!

juliancwirko commented 2 years ago

Hey, thank you. Do you mean MultiESDTNFTTransfer?

useTransaction hook https://github.com/ElrondDevGuild/nextjs-dapp-template/blob/main/components/demo/SimpleEGLDTxDemo.tsx#L21

gives you triggerTx function https://github.com/ElrondDevGuild/nextjs-dapp-template/blob/fc34df4cd45af7f75202d4003e43a7189263ce43/hooks/core/useTransaction.tsx#L53

which takes:

address,
data,
gasLimit,
value,

so everything that the MultiESDTNFTTransfer transaction needs (sender will be set automatically, and receiver should be the same as the sender) https://docs.elrond.com/developers/esdt-tokens/#multiple-tokens-transfer

The most problematic here is the data payload. You can build it like that:

import {
  TokenPayment,
  Transaction,
  MultiESDTNFTTransferPayloadBuilder,
  Address,
} from '@elrondnetwork/erdjs';

(...)

let paymentOne = TokenPayment.nonFungible("ERDJS-38f249", 1);
let paymentTwo = TokenPayment.fungibleFromAmount("BAR-c80d29", "10.00", 18);
let payments = [paymentOne, paymentTwo];
let payload = new MultiESDTNFTTransferPayloadBuilder()
    .setPayments(payments)
    .setDestination(new Address("erd1...")) // receiver address
    .build();

(...)

// triggerTx from useTransaction hook
triggerTx({
    address: erd1..., // address string here, normally receiver address, here it will be the same address as yours (the sender)
    gasLimit: 50000 + 1500 * data.length() + 1000000 * payments.length,
    data: payload,
    value: 0,
  });

(...)

I haven't tested it. You can read more about how to prepare TokenPayment instances here: https://docs.elrond.com/sdk-and-tools/erdjs/erdjs-cookbook/#preparing-payment-objects.

But generally, the useTransaction hook gives a universal tool for probably most types of transactions. The only important thing is the transaction data payload and receiver address. Sometimes, it is the same as the sender because of build-in functions like here. And there is also useScTransaction smart contracts transactions.

juliancwirko commented 2 years ago

For a custom smart contract, it will probably be similar. You would need to use the useScTransaction, which also gives triggerTx with

smartContractAddress,
func,
gasLimit,
args,
value,

The data payload could differ. I would need to check how standard multi-payment is usually done.

Alannek1992 commented 2 years ago

Thanks for quick reply. The only thing what I wonder right now is how to provide an endpoint name for the SC.

Using MultiESDTPayloadBuilder is possible to provide payment and destination, but not the endpoint name.

juliancwirko commented 2 years ago

do you need to handle something like this?

#[endpoint]
  #[payable("*")]
  fn payment_array_3(&self) -> MultiValue3<EsdtTokenPayment, EsdtTokenPayment, EsdtTokenPayment> {
      let [payment_a, payment_b, payment_c] = self.call_value().multi_esdt();
      (payment_a, payment_b, payment_c).into()
  }
Alannek1992 commented 2 years ago

Yea, very similar

Alannek1992 commented 2 years ago

This approach works for me, but probably there is better way to do that


const payload = TransactionPayload.contractCall()
            .setFunction(new ContractFunction("MultiESDTNFTTransfer"))
            .setArgs([
                new AddressValue(this.address),
                new U32Value(3),
                BytesValue.fromUTF8(this.config.nftToken),
                new U64Value(nonce1),
                new BigUIntValue(new BigNumber(1)),
                BytesValue.fromUTF8(this.config.nftToken),
                new U64Value(nonce2),
                new BigUIntValue(new BigNumber(1)),
                BytesValue.fromUTF8(this.config.nftToken),
                new U64Value(nonce3),
                new BigUIntValue(new BigNumber(1)),
                BytesValue.fromUTF8("yourFunc"),
            ])
            .build();
        return new Transaction({
            receiver: sender,
            gasLimit: 20000000,
            data: payload,
            chainID: this.elrondService.networkConfig.ChainID,
        });
juliancwirko commented 2 years ago

Yes, this should also work with built-in MultiESDTNFTTransfer, but from what I understand you have a custom smart contract with the endpoint that takes multi-value esdt payments, right?

I haven't implemented any similar tx call to such custom sc endpoint yet, but I would probably search through erdjs VariadicType and CompositeType to create proper args for triggerTx from useScTransaction:

triggerTx({
    smartContractAddress: yourScAddressHere,
    func: new ContractFunction(yourEndpointNameHere),
    gasLimit: requiredGasLimitForYourCustomScEndpoint,
    args: [], // here we need to pass the multi value esdt data as argument, probably using `VariadicType` or `CompositeType` from erdjs
    value: 0, // value will be 0
  });

These are my guessing. I haven't tested it yet. But anyway, the dapp has the tools, the most problematic is how to prepare the data payload or how to prepare the args, like here.

Btw. Check here: https://github.com/ElrondNetwork/elrond-sdk-erdjs/blob/main/src/smartcontracts/typesystem/typeMapper.spec.ts. Maybe this will help.

And docs on variadic types: https://docs.elrond.com/developers/best-practices/multi-values/#variadic-inputs-and-outputs-multi-values

Alannek1992 commented 2 years ago

Thanks a lot for your hints and clarification!

I think this issue can be closed.

juliancwirko commented 2 years ago

Sure, let us know if you will find a way for args with erdjs. I'll try to play with such cases more. It would be an excellent addition to the scrolls gitbook. I mean the page with real-life examples. So how to call custom smart contracts endpoints with more complicated data structures using erdjs.

juliancwirko commented 2 years ago

It could be that my thinking about the custom call and custom args is wrong. From what I see here: https://docs.elrond.com/sdk-and-tools/erdpy/smart-contract-interactions/#multi-esdt-transfer looks like the MultiESDTNFTTransfer should always be called, even in the case of a custom smart contract, as an addition there is an endpoint call, so precisely what you pasted before, but with erdjs. I need to find some time to play around with ESDT payments, finally ;)