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

[Feature request] expose implemented traits via interface RPC API #2382

Closed
hstove opened this issue Jan 26, 2021 · 9 comments · Fixed by #2498
Closed

[Feature request] expose implemented traits via interface RPC API #2382

hstove opened this issue Jan 26, 2021 · 9 comments · Fixed by #2498
Assignees
Labels
enhancement Iterations on existing features or infrastructure.

Comments

@hstove
Copy link
Contributor

hstove commented Jan 26, 2021

Is your feature request related to a problem? Please describe.
I already have functionality in the Stacks Wallet for Web that allows users to natively transfer fungible tokens and see their balances. When the user goes to do a transfer, I fetch the interface for that contract, and then check if it has a function with the signature (transfer (recipient principal) (amount uint)). If it has this function, I allow the contract-call, add default post conditions, etc. It's pretty cool and all thanks to all the work already implemented in this repo and the API!

However, I don't fully know that the contract follows a trait. If I want to fetch the token's name, decimals, etc, I'd have to do a bunch of read-only calls. Or, I can create a wrapper contract that does use-trait and fetches that read-only info in the wrapper.

Ultimately, it would be awesome to expose the implemented traits via RPC. Wallets could fetch the interface and simply check if a "hard-coded" trait is implemented.

Describe the solution you'd like
In /v2/contracts/interface/SPXX/name, expose in the JSON something like:

{
  implemented_traits: [
    'SPXX.name.trait'
  ],
  // other existing fields
}

For example, I could build a wrapper contract to fetch the info I need. What if I want to build a contract registry? All the stuff I need is already in Clarity (i.e. use-trait). However, if I was building a UI layer for the registry, it'd be best to first check that the trait is implemented. Otherwise, I'd have to make a contract call on my registry contract and wait to see if it was rejected.

Describe alternatives you've considered
Wrapper contracts, registry contracts, etc get us pretty much all the way there, but exposing via the interface would be better.

Other context

Friedger and I have started proposing SIPs for traits, which is a first step, and this would make traits even more powerful.

stacksgov/sips#5 and stacksgov/sips#3

@project-bot project-bot bot added this to New Issues in Stacks Blockchain Board Jan 26, 2021
@jcnelson
Copy link
Member

jcnelson commented Jan 26, 2021

I think it should be possible to handle the special case where a contract explicitly declares which trait(s) it uses. Then we could maintain an index in the analysis DB that would let you read the list of traits a particular contract implements, and the list of contracts that explicitly use a particular trait.

Listing out which contracts implement a particular trait is going to be harder, since a contract can implement a trait that hasn't been declared yet. This is why a contract-call requires you to name both the trait and the implementation -- the contract-call type-checks the implementation against the trait right then and there, so it won't matter where in the blockchain history a particular trait was declared relative to the implementation. For example, you could deploy a contract whose interfaces happens to match a future fungible-token SIP's trait, and be able to use that trait with the contract in a future contract-call (because it "retroactively implements" the trait).

Efficiently maintaining an index over which contracts just so happen to implement which traits will require more thought. I'm skeptical it could be done efficiently -- each new contract would need to be type-checked against each existing trait, and the work required to do this for a new contract ought to grow at least linearly with the number of traits. Also, each new trait would need to be checked against all existing contracts in order to determine which contracts to list out when the trait is queried.
@kantai is more qualified than I am to talk about the feasibility of this, so I'll defer to him for how to solve this in the general case.

@hstove
Copy link
Contributor Author

hstove commented Jan 26, 2021

It would certainly be nice to be able to query all contracts that implement a trait. Are you saying that indexing the traits implemented for a specific contract is just as hard? If I had to choose one, I believe that "list which traits are implemented by this contract" as more valuable. If we had that, then the API server could maintain the backwards index, potentially.

a contract can implement a trait that hasn't been declared yet

Is that true? I just tried this, and the contract deploy was abort_by_response. Deploying the same contract again after deploying the trait first is a success.

@hstove
Copy link
Contributor Author

hstove commented Jan 26, 2021

@friedger why the thumbs down reaction to this issue?

@kantai kantai added the enhancement Iterations on existing features or infrastructure. label Feb 26, 2021
@kantai
Copy link
Member

kantai commented Feb 26, 2021

I agree with @hstove that "list which traits are implemented by this contract" is the most valuable first step here, and I think the Clarity analysis module already computes this (would have to check whether or not it gets stored in the analysis db, though, but that's a pretty straightforward change).

@friedger
Copy link
Collaborator

friedger commented Feb 28, 2021

An endpoint to check whether a contract implements one (or a list of) certain trait makes more sense to me because traits can appear in the future.

@kantai Whenever a trait is deployed all contract will be analysed whether they implement that trait?

@kantai
Copy link
Member

kantai commented Feb 28, 2021

An endpoint to check whether a contract implements one (or a list of) certain trait makes more sense to me because traits can appear in the future.

Good point -- something like /v2/traits/<contract>/<trait-to-check> that returned whether or not that trait was implemented would be useful for that.

@kantai Whenever a trait is deployed all contract will be analysed whether they implement that trait?

No -- there's basically two "paths" for trait implementation: explicit and implicit. For explicit implementation, the contract specifies that it implements a given trait (which is checked and enforced by the analyzer). These implementations must be broadcast after the trait definition. For implicit implementation, a contract caller attempts to use a given contract as a trait implementation, without the called contract explicitly having implemented the trait. Those are only checked at the time of the transaction (currently at runtime, but could be checked by a static analyzer as well). These would have different consequences for a trait RPC; for explicit implementations, we can return the list of explicitly implemented traits for any contract, but for implicit implementations, we can only check the implementation once we know what trait is being checked.

@friedger
Copy link
Collaborator

Therefore, the suggested endpoint is only partly useful as it would only return explicit trait implementations.

@hstove
Copy link
Contributor Author

hstove commented Mar 6, 2021

Hm, so if I'm reading this right, if I have this code:

(use-trait ft-trait 'ST3J2GVMMM2R07ZFBJDWTYEYAR8FZH5WKDTFJ9AHA.ft-trait.ft-trait)

(define-public (name (token <ft-trait>))
  (ok (contract-call? token name))
)

You can validly pass a contract that doesn't explicitly have impl-trait in it? If so, that's pretty handy, and I didn't know that.

@pavitthrap pavitthrap moved this from New Issues to Done in Stacks Blockchain Board Mar 15, 2021
@pavitthrap
Copy link
Contributor

Hm, so if I'm reading this right, if I have this code:

(use-trait ft-trait 'ST3J2GVMMM2R07ZFBJDWTYEYAR8FZH5WKDTFJ9AHA.ft-trait.ft-trait)

(define-public (name (token <ft-trait>))
  (ok (contract-call? token name))
)

You can validly pass a contract that doesn't explicitly have impl-trait in it? If so, that's pretty handy, and I didn't know that.

Yes, that is correct @hstove - the endpoint checks for implicit implementations as well (no impl-trait call).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Iterations on existing features or infrastructure.
Projects
Development

Successfully merging a pull request may close this issue.

5 participants