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

feat: add Into for Address and ContractId fn arguments #967

Merged
merged 14 commits into from
May 26, 2023

Conversation

hal3e
Copy link
Contributor

@hal3e hal3e commented May 15, 2023

closes: #962

Our FunctionGenerator now generates impl Into<Bech32Address> and impl Into<Bech32ContractId> instead of Address and ContractId.

This is reflected on all contract methods, predicate encode functions, and script main functions.

Checklist

  • I have linked to any relevant issues.
  • I have added necessary labels.
  • I have done my best to ensure that my PR adheres to the Fuel Labs Code Review Standards.
  • I have requested a review from the relevant team or maintainers.

@hal3e hal3e added the enhancement New feature or request label May 15, 2023
@hal3e hal3e requested a review from a team May 15, 2023 14:53
@hal3e hal3e self-assigned this May 15, 2023
Br1ght0ne
Br1ght0ne previously approved these changes May 16, 2023
Copy link
Contributor

@iqdecay iqdecay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question on design

Copy link
Contributor

@iqdecay iqdecay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this would enable the user to pass in an Address to a method that normally only accepts ContractId without being explicit about it, and this is not something we want. It needs to be explicit, because the difference between Address and ContractId is fundamental and can lead to a loss of fund IIUC. Am I getting this wrong?

@hal3e
Copy link
Contributor Author

hal3e commented May 19, 2023

I feel like this would enable the user to pass in an Address to a method that normally only accepts ContractId without being explicit about it, and this is not something we want. It needs to be explicit, because the difference between Address and ContractId is fundamental and can lead to a loss of fund IIUC. Am I getting this wrong?

You are right. Normally it would not be a problem to have a impl Into<ContractId> as I would imagine that into would be implemented only for types that make sense. However, we will get into implementations for conversion between Address and ContractId and then we do not have type safety anymore.

The only other thing that comes to mind is to have methods accept Bech32Address and Bech32ContractId. However, this solution is not as ergonomic as impl Into<ContractId> as you would have to turn an already existing ContractID into Bech32ContractId (same applies to Address)

@FuelLabs/sdk-rust what are you thoughts on this? I am leaning towards leaving it as is and closing this PR.

@segfault-magnet
Copy link
Contributor

I feel like this would enable the user to pass in an Address to a method that normally only accepts ContractId without being explicit about it, and this is not something we want. It needs to be explicit, because the difference between Address and ContractId is fundamental and can lead to a loss of fund IIUC. Am I getting this wrong?

You are right. Normally it would not be a problem to have a impl Into<ContractId> as I would imagine that into would be implemented only for types that make sense. However, we will get into implementations for conversion between Address and ContractId and then we do not have type safety anymore.

The only other thing that comes to mind is to have methods accept Bech32Address and Bech32ContractId. However, this solution is not as ergonomic as impl Into<ContractId> as you would have to turn an already existing ContractID into Bech32ContractId (same applies to Address)

@FuelLabs/sdk-rust what are you thoughts on this? I am leaning towards leaving it as is and closing this PR.

What about replacing the usages of Address with impl Into<Bech32Address> in the generated fn bindings?

So you can then give both an Address and its bech32 equivalent. Same for the ContractIds.

You'd retain type safety since neither Address satisfies impl Into<Bech32ContractId> nor does ContractId satisfy impl Into<Bech32Address>.

You'd still have pure addresses nested in generated structs and enums, since using impl there would cause generic headaches.

@iqdecay
Copy link
Contributor

iqdecay commented May 20, 2023

I would like the Into<Bech32Address> and Into<Bech32ContractId>, but sending something to a Bech32Address vs its corresponding Address doesn't work I think. If they are not functionaly equivalent, I'm for keeping type safety above all, otherwise users would probably shoot themselves in the foot.
But it does ask the question of why we are bothering users with implementation details of exposing the Bech32 format at all, IMO we should discuss around how to abstract this away.

@hal3e
Copy link
Contributor Author

hal3e commented May 21, 2023

What about replacing the usages of Address with impl Into<Bech32Address> in the generated fn bindings?

So you can then give both an Address and its bech32 equivalent. Same for the ContractIds.

You'd retain type safety since neither Address satisfies impl Into<Bech32ContractId> nor does ContractId satisfy impl Into<Bech32Address>.

You'd still have pure addresses nested in generated structs and enums, since using impl there would cause generic headaches.

This is a great idea! ❤️ I did a quick first implementation and it works as expected. We retain the type safety as you said.

@iqdecay you said:

but sending something to a Bech32Address vs its corresponding Address doesn't work I think.

We turn it back to an Address under the hood so everything works the same. The interface is just a bit nicer as you can give either an Address or a Bech32Address

@hal3e hal3e requested a review from a team May 22, 2023 08:59
@iqdecay
Copy link
Contributor

iqdecay commented May 23, 2023

What I meant is I think that rather than changing this implementation detail, we should re-explore why we are exposing two types of addresses at all. Fixing this seems like a bandaid to the more general problem of exposing two types of addresses instead of handling them both under the hood. This particular fix is moreover not the one requested by user (because the one requested by users is a gateway to a footgun), so we don't actuallly need to do it IMO.

@hal3e
Copy link
Contributor Author

hal3e commented May 23, 2023

What I meant is I think that rather than changing this implementation detail, we should re-explore why we are exposing two types of addresses at all. Fixing this seems like a bandaid to the more general problem of exposing two types of addresses instead of handling them both under the hood. This particular fix is moreover not the one requested by user (because the one requested by users is a gateway to a footgun), so we don't actuallly need to do it IMO.

I agree but what you say is above this request. The user wanted a nice UI where he can give either Address or Bech32Address (same for ContractId) to contract methods. This PR makes that possible without losing type safety. So until we have an unified Address and ContractId IMO it makes sense to have this.

@iqdecay
Copy link
Contributor

iqdecay commented May 23, 2023

Ah yes you're right mb

@hal3e hal3e requested a review from a team May 23, 2023 16:23
@iqdecay
Copy link
Contributor

iqdecay commented May 24, 2023

I'm sorry but I really don't want to merge anything before the fuel-core 0.18 is merged

Copy link
Contributor

@segfault-magnet segfault-magnet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff.

Copy link
Member

@Salka1988 Salka1988 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@iqdecay iqdecay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@hal3e hal3e merged commit a4b08ba into master May 26, 2023
32 checks passed
@hal3e hal3e deleted the hal3e/into-address-contractId branch May 26, 2023 16:44
@SwayStar123
Copy link
Member

Thank you hal3e, very cool

@diyahir
Copy link

diyahir commented Jun 15, 2023

Could we not determine if it's a contract or address at run-time and avoid casting it altogether?

Casting it only at runtime for the pieces that must know

@diyahir
Copy link

diyahir commented Jun 17, 2023

If I give you an address 0x123....789, and I say to send it 10 ETH, is it fair to say you could get an error depending on if it's a contractId or an address, so you would need to ask me a follow-up, is it an address or a contract. Well a multisig is a contract, but I could see someone making that mistake.

It seems like we're building a 'gotcha' into the sway stack that could be avoided entirely if we just abstract all of this into a run-time check (if possible, if not possible currently then add a flag to each address?)

@iqdecay
Copy link
Contributor

iqdecay commented Jun 17, 2023

This is a good argument I agree, but this is not the right place to discuss it, this issue is. This design decision is not ours, and even if we wanted we cannot change it, it's in Sway.

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

Successfully merging this pull request may close these issues.

Change contract methods to accept Into<Address> and Into<ContractId> instead of Address and ContractId
7 participants