Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Alannek1992 opened this issue Jun 23, 2022 · 10 comments

Comments

@Alannek1992
Copy link

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!

@Alannek1992 Alannek1992 changed the title Support for MultiESDT transactions Support for calling smart contract endpoints, which expect MultiESDT payment Jun 23, 2022
@juliancwirko
Copy link
Member

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
Copy link
Member

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
Copy link
Author

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
Copy link
Member

juliancwirko commented Jun 23, 2022

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
Copy link
Author

Yea, very similar

@Alannek1992
Copy link
Author

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
Copy link
Member

juliancwirko commented Jun 23, 2022

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
Copy link
Author

Thanks a lot for your hints and clarification!

I think this issue can be closed.

@juliancwirko
Copy link
Member

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
Copy link
Member

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 ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants