Web3.py: Flip the contract function calls

Created on 13 Nov 2017  路  37Comments  路  Source: ethereum/web3.py

  • Version: 4

What was wrong?

The order of calls (contract.call().doSomething()) could be more intuitive.

How can it be fixed?

Basic Approach

web3.js seems to have a solid solution: contract.functions.method().call()

Plus:

  • ..method().transact()
  • ..method().estimateGas()
  • etc

This API can coexist alongside the old way of calling contract methods.

API Naming

functions is a little long, here are some other options:

  • contract.api.doSomething().call()
  • contract.public.doSomething().call()
  • contract.build.doSomething().call()
  • contract.make.doSomething().call()
  • contract.prep.doSomething().call()
  • contract.useabi.doSomething().call()
  • contract.go.doSomething().call()
  • contract.methods.doSomething().call() _Added_

Also, think about how the name will sound when used with other execution options, like transact, estimateGas, and buildTransaction

Requirements

  • [ ] add new API
  • [ ] document new API in docs/
  • [ ] add deprecation warning to old call/transact/etc methods
  • [ ] Bonus: Update ConciseContract to use the new Contract API under the hood (with no change to the external API)
Good First Issue

Most helpful comment

Is anyone working on this? If not, I would like to give it a try.

All 37 comments

I would add contract.methods.doSomething().call() to the list to be considered.

I also like api but I'm not a fan of how broad a concept API is. I think some users might assume that events are available under api as well when I think they belong under contract.events.MyEvent().

Good point about the events disambiguation. That invokes another alternative, which is to mirror the word in the type field from the abi json spec exactly. By that, I mean:

  • myContract.function.myMethod().transact()
  • myContract.event.myMethod().transact()
  • myContract.constructor.args().transact()
  • myContract.fallback.transact()

But as is apparent above, it does lead to some non-parallel APIs in the constructor and fallback, which makes me sad.

I don't exactly follow your meaning here:

But as is apparent above, it does lead to some non-parallel APIs in the constructor and fallback, which makes me sad.

I like the api you list above (function/event/constructor/fallback) though my spider sense says that special casing fallback and constructor might be wrong though that is a very weak might and on the surface I can find no reason not to do it.

I don't exactly follow your meaning here:

But as is apparent above, it does lead to some non-parallel APIs in the constructor and fallback, which makes me sad.

What I meant is that the first two examples were in the format: <contract>.<abi_type>.<abi_name>(<args>).transact(), and the third and fourth examples broke that pattern. In the case of constructor and fallback, no name is defined in the ABI. The third and fourth even differ from each other, because the constructor may take arguments, and the fallback may not.

my spider sense says that special casing fallback and constructor _might_ be wrong

When half of the cases are special cases, and their specialness is different from even each other, it feels like we don't have the right model yet.

Here's a stab at making "rules" about the naming:

If there is no name, you invoke it directly. If there is a name, you invoke it as an attribute. That starts to look consistent:

myContract.function.myMethod().transact()
myContract.event.myMethod().transact()
myContract.constructor().transact()
myContract.fallback().transact()

Further, any of them may skip the parens if it is valid to work with zero arguments:

myContract.function.myMethod.transact()
myContract.event.myMethod.transact()
myContract.constructor.transact()
myContract.fallback.transact()

We're approaching self-consistency, and consistency with the ABI. But we're heading in the opposite direction of the succinctness that I find in my favorite APIs. So I'm not celebrating yet.

__This issue now has a funding of 0.335 ETH (110.39 USDT) attached to it.__ To view or claim this funding, click here.

Just had a thought about fallback. It may make sense to support calling it a few ways.

# 1. with some params that need to be abi encoded (which would then be injected into the `data` portion of the transaction
myContract.fallback(args=[1, b'arst', True], abi=['uint256', 'bytes32', 'bool']).transact()
# 2. with params that need to be encoded in 2-tuples
myContract.fallback(args=[(1, 'uint256'), (b'arst', 'bytes32'), (True, 'bool')])
# 3. with pre-encoded data as binary or hex
myContract.fallback(b'...').transact()
myContract.fallback(hexstr='0x12345abcde').transact()

Not critical functionality and not required for MVP, but worth thinking about as we evolve this API.

Wait, you mean to transact with constructors or other things, right? I thought that if you send data, you're no longer interacting with the fallback...

I thought that if you send data, you're no longer interacting with the fallback...

Only if the first four bytes of the data happen to match one of the existing function selectors of the contract.

btw, this type of interaction with the fallback function is what I would consider very advanced functionality and would be of little use to the vast majority of our users.

It would however be useful for security research and other research based things.

I thought that if you send data, you're no longer interacting with the fallback...

Only if the first four bytes of the data happen to match one of the existing function selectors of the contract.

Of course :man_facepalming: . Yeah, those examples make sense to me now.

Is anyone working on this? If not, I would like to give it a try.

@dylanjw all you!

If we had really nailed the naming, I don't think there would have been so much discussion on it in #481.

Open questions:

  1. Do we always use the ABI type name exactly, or do we pluralize function and event?
  2. Do we allow invoking anything without parentheses? (like myContract.fallback.transact() or myContract.function.myMethod.transact())

Maybe this alternative would feel cleaner?

myContract.function_myMethod().transact()
myContract.event_myEvent().transact()
myContract.constructor().transact()
myContract.fallback().transact()

That answers these questions this way:

  1. We always use the ABI type name exactly, because plural reference doesn't fit anymore.
  2. We always require explicit parentheses to invoke the function.

Thoughts @pipermerriam @dylanjw ?

@dylanjw how goes it?

There was a checkin a couple days ago and feedback yesterday, so it's still active.

430 is merged now, notice the new action buildTransaction

@carver Your suggestion feel cleaner, but Im wondering if will limit extensibility. I noticed in the web3.js api they allow some alternatives for function selection:

The name: myContract.methods.myMethod(123)
The name with parameters: myContract.methods['myMethod(uint256)'](123)
The signature: myContract.methods['0x58cf5f10'](123)

Not that we should copy this exactly, but it shows having a discreet function/event attribute may provide some flexibility. Im leaning more towards piper's request for the pluralized api: contract.functions, contract.events.

The events piece requires some extra thought, since the other three are things you can directly create a transaction with, but AFAIK there's no such thing with an event.

So what are the methods available under events? See #429 (esp. the first half) for an example of what people need under events. Since this isn't a thing that exists in the original order (ie~ there is no contract.call().eventName()) I think it would be okay to punt this out of the PR and come back to it in a separate one.

Supporting both of these would be nice since the auto-matching of what function you are trying to call can fail in certain edge cases.

  • The name with parameters: myContract.methods['myMethod(uint256)'](123)
  • The signature: myContract.methods['0x58cf5f10'](123)

hey @dylanjw -- the bounty is scheduled to expire in 4 days. is this still something you want to turn around?

@owocki Yes. I just need to make updates to the documentation and get the pull request reviewed. Can we extend the deadline? Im planning to wrap it up this weekend.

@dylanjw sure no problem. hit me up this weekend

gonna do a round of payouts on tuesday. @ me back if you submit that documentation by then :)

@dylanjw hows it going? no pressure, just checking in

@owocki Im working on resolving some tests I broke.

@owocki I noticed @step21 has claimed this issue in gitcoin since I have started working on it.

Yeah, sorry about that. I guess I didn't check the issue properly to see that you started already as I was just happy that finally claiming something worked. Would have loved to work on it too, but I don't think I can unclaim it, can I?

@step21 we'll have some more bounty'd issues here within a week or two. Stay tuned.

No worries, but sorry about the mixup @dylanjw

my apologies folks. were working out how to scale the issue claiming process.. duplicate work is understandably a real gumption trap, so i genuinely apologies and we hope to avoid this in the future.

@dylanjw mind claiming the issue at https://gitcoin.co/funding/details?url=https://github.com/pipermerriam/web3.py/issues/419 ?

Howdy @dylanjw, I recently joined @owocki at Gitcoin. Checking in to make sure all is going well :)

Hi @vs77bb #481 has been merged, so I think this can be closed and paid out if @carver gives the ok.

Payout approved! :tophat:

Wonderful! cc @owocki

@dylanjw can you claim the bounty over at https://gitcoin.co/funding/details?url=https://github.com/pipermerriam/web3.py/issues/419 so i can pay it out to you ? thanks :)

@owocki Done. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

locpv-ibl picture locpv-ibl  路  4Comments

Netherdrake picture Netherdrake  路  3Comments

kclowes picture kclowes  路  3Comments

venkatBGit picture venkatBGit  路  4Comments

carver picture carver  路  4Comments