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

Can't get HTS token address when creating the token using the interface IHederaTokenService #901

Open
ed-marquez opened this issue Aug 12, 2024 · 4 comments
Assignees
Labels
bug Something isn't working HTS Hedera Token Service related

Comments

@ed-marquez
Copy link

Description

Problem:
When creating an HTS token using the interface IHederaTokenService, a developer can't get the token address using Ethers JS.

Context:

  • IHederaTokenService (see file here) has the function createNonFungibleToken which returns (int64 responseCode, address tokenAddress);
  • I currently have the JS code shown in the screenshot (see full code in this repo), which successfully creates the token calling the function createNonFungibleToken.
  • Despite the token creation working well, I can’t get the address of the newly created token using Ethers.
    -- Decomposing the transaction output does not return the responseCode or the tokenAddress. I think this works when creating the token through a wrapper/intermediary contract, but it doesn’t seem to work when calling the system contract using the interface…
    -- The logs of the tx receipt are empty and there are no events.

image

For devs working with Ethers/Hardhat, those tools only return a transaction hash (no tx ID).
The mirror node REST API supports querying transactions with our 48-byte form of the tx hash, not the Ethereum 32-bytes one. So querying mirror nodes with the tx hashed obtained would not be seamless either.

Possible Solution:

  • We are emitting a log for HTS transfers.
  • We could assimilate the creation of a new token as the creation of a new smart contract, so we can use the same format for the receipt. That would be something all the Ethereum tools can easily understand and work with out of the box, without having to rely on custom logs.

Thanks to everyone who provided feedback and input!

Steps to reproduce

  1. Run this repo with GitPod via this link: https://gitpod.io/?autostart=true#https://github.com/ed-marquez/hedera-example-create-tokens-via-contracts/tree/5351753720d3db77cfab098834527fae1eafa299
  2. Enter npx hardhat test on the terminal
  3. See the results of the 3rd test case

Additional context

No response

Hedera network

mainnet, testnet

Version

v0.52

Operating system

macOS

@ed-marquez ed-marquez added the bug Something isn't working label Aug 12, 2024
@Nana-EC Nana-EC moved this from Backlog to Sprint Backlog in Smart Contract Sprint Board Sep 11, 2024
@Nana-EC Nana-EC added the HTS Hedera Token Service related label Sep 11, 2024
@konstantinabl konstantinabl self-assigned this Nov 1, 2024
@konstantinabl konstantinabl moved this from Sprint Backlog to Tasks In Progress in Smart Contract Sprint Board Nov 1, 2024
@konstantinabl
Copy link
Contributor

konstantinabl commented Nov 7, 2024

As you stated in your ticket there are indeed two possible solutions here.
The first to emit an event, when a token is created. This however will result in us not being 100% equivalent with ERC20, since theres no such event there.
The second option is to return the contractAddress field as part of the receipt, this will require some changes in the relay and might slightly slowdown the getReceipt endpoint, due to the fact that we will have to check the selector that was called with the transaction and if it is createFungible/createNonFungible etc.
Two things to note here:

  1. Doing this won't be optimal for the cases where there's a nested call creating the token. Not sure if such cases are commont, though.
  2. It will require an extra step, where after getting the address from the receipt the user will have to do something like this to use the token as an ERC20
    const tokenAddress = tokenCreateTx.contractAddress;
    const tokenAsErc20 = await ethers.getContractAt(ERC20ABI, tokenAddress);
    We'll discuss whats best

cc: @Nana-EC

@Nana-EC
Copy link
Collaborator

Nana-EC commented Nov 8, 2024

Thanks @ed-marquez these are fair points and @konstantinabl has highlighted some tradeoffs.
In general we want to utilize the existing behaviour that EVM devs expect.
Both logs and the address solution speak to that but they also fuse EVM and specific product considerations.

Ethers offers the contractFactory which handles both the deployment and getting the new contract address.
It does this I believe by calculating the address based on EVM logic. In our case a new HTS token address is not predictable offchain and we need to get it from the network.

@konstantinabl expanding on the second suggestion of tokenCreateTx.contractAddress we should look at an example of this call.
As you'd noted we'd have to confirm the function selector, then we'd have to make a call to MN to get the token details.
What all steps might the relay have to take in this case and are there any edge cases where it wouldn't work?
This will help us get a sense of feasibility and latency/perf concerns.

I'm biased towards a non CN change except we'd also have to consider how the MN web3 module would replicate this on direct calls to it's API outside of the relay

@konstantinabl
Copy link
Contributor

@Nana-EC so regarding adding the tx.contractAddress I tested it and it currently returns the field, but it has the 0x167 address. So what we need to do is return the actual address of the token that was created. This can be done without extra calls, in the receipt we have the data and the function selector + the result of the function, which in this case is the responseCode + tokenAddress.
The tradeoff here is if function selectors are changed in services we will have to manually change in our repo, but I guess this won't happen often. Also this will work only for direct calls, so wont return the tokenAddress of the created token if there is a nested call, but I guess this is the idea of the issue.

@Nana-EC
Copy link
Collaborator

Nana-EC commented Nov 12, 2024

@Nana-EC so regarding adding the tx.contractAddress I tested it and it currently returns the field, but it has the 0x167 address. So what we need to do is return the actual address of the token that was created. This can be done without extra calls, in the receipt we have the data and the function selector + the result of the function, which in this case is the responseCode + tokenAddress. The tradeoff here is if function selectors are changed in services we will have to manually change in our repo, but I guess this won't happen often. Also this will work only for direct calls, so wont return the tokenAddress of the created token if there is a nested call, but I guess this is the idea of the issue.

Thanks @konstantinabl good idea.
Please go ahead and start on a design doc for this suggested feature so we can get a review and discussion going.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working HTS Hedera Token Service related
Projects
Status: Tasks In Progress
Development

When branches are created from issues, their pull requests are automatically linked.

3 participants