EIP-5792 - Wallet Function Call API

For something like complex transaction building (e.g. furucombo) you usually want to involve a smart contract to introduce logic between the calls (e.g. all or nothing, these 2 calls are optional, take output of this call and pass as input to another call). Furucombo still greatly benefits from this EIP because the spending approvals can be batched with the function calls you want to make. The one drawback is the calls do not come from the user’s wallet. But I’m not sure if support for that is really required for any meaningful transaction building use case.

I’m on the fence. I want this interface to be as narrow and abstract as possible so as to prevent dapps from building branching logic based on wallet capabilities, which either adds work for the dapp developer or excludes wallets. The “atomic” flag definitely leaks wallet implementation details to the dapp. But if people are strongly in favor of this change I’ll add it–I’m definitely more ok with atomic flag than 3 different levels of atomicity which feels even leakier.

My two cents on this is I’d think early adopters will want account abstracted wallets for better security/recovery, or other features they offer. I myself am a user of a smart contract wallet, and many of my friends use gnosis safe for self custody. I’m not sure if that changes the calculus.

Yup, makes sense, totally get what’s being asked for here.

1 Like

Hey everyone, wanted to add that we have added support for EIP-5792 for CANDIDE mobile Wallet. We are supporting the three methods:

  • wallet_sendFunctionCallBundle
  • wallet_getBundleStatus
  • wallet_showBundleStatus

Here’s our implementation for other wallet developers to reference:

Documentation for dapp developers wishing to support bundle calls in their app, along with a codesanbox to start experimenting with. We wrote examples for Web3Modal and WalletConnect Standalone:

1 Like

In the absence of this method, does it make sense to add one to the EIP just for checking if this particular set of methods is supported? Reviewing the guide posted by @marc and thinking about this again, I can’t imagine implementing this in a mature dapp and falling back to multiple eth_sendTransaction calls as I originally proposed. There will need to be a transitional period where a dapp needs to support both existing wallet APIs well and the function call bundle API.

Such a method could look like: wallet_isFunctionCallBundleSupported with no parameters, returns true if supported and errors or returns false if not supported.

I’d like to revive the discussion regarding the EIP as we continue our efforts to call for both wallet and dapps to integrate it.

Recently, we worked with PoolTogether to develop a more user-friendly interface for the no-loss donation use case. This involved a multi-step interaction process comprising 6 batch transactions, which included granting approval for the contract, depositing funds, and delegating winnings to another address. We didn’t encountered issues. Note that we built the frontend from the ground up to support exclusively batch transactions. There’s no way for an EOA to interact with it.

Net steps we will assist two dapps in integrating this EIP into their interfaces. Since these dapps already support the standard EOA workflow. We will be adding support for batch transactions if a smart wallet is connected. I will keep updates posted as they progress.

After Tweeting with only a vague recollection of this discussion, I accidentally discovered another axis I think should be covered by the endpoint: what happens on failure in the none case. Here are all the options now:

  • "atomicity": "continue-on-fail" → Send all the transactions even if some fail.
  • "atomicity": "stop-on-fail" → Stop on first failed operation. Operations successfully executed so far MUST NOT be reverted.
  • "atomicity": "loose-revert-on-fail" → If any operations fail, none of the operations should happen (they should either revert or not appear on-chain.) This could be implemented for EOAs with flashbots. May lose atomicity in the face of reorgs.
  • "atomicity": "strict-revert-on-fail" → If any operations fail, all operations MUST either revert or never appear on-chain. Must remain atomic in the face of reorgs.
2 Likes

This EIP is stagnant, is there anything wrong?

I’ve been working on atomic:

Maybe I can help you

2 Likes

Guys, we're so back.

  • A new PR bumped the status from stagnant to draft: EIPs#8361
  • And I also opened a PR of my own, #8396, trying to incorporate suggestions made in the 8361 comments and elsewhere, to continue the refinement.
  • Related PRs might be opening soon on capability and/or permissions expressions and discovery, so I’m hoping this stays “Draft” long enough to cross-reference other relevant drafts.
1 Like

Should this proposal specify the error response when two conflicting capabilities are requested in the same batch?

1 Like

In general, I’d be supportive of that because wallet_getCapabilities is defined here so its failure modes or expectations should be defined here, but this EIP only specifies one capabilities so I worry the burden of defining what might contradict with atomicBatch falls on the future EIP defining a second capability related enough to contradict it, wouldn’t it?

Were you thinking a strong fail (e.g. 1.)
a calling app MUST NOT use either capability if two returned capabilities are contradictory in ways defined by either capability's specification
, or a no-obligation (e.g. 2.)
a calling app MAY ignore the behavior specified by a returned capability if that capability is logically contradicted by another returned capability
?

I was thinking something along the lines of:

If a wallet is unable to fulfill a request because it contains two or more incompatible capabilities, it MUST reply with an RPC error code of 7

Oh, ok, you’re talking about if the REQUEST contains two capabilities that can’t both be granted at the same time, I’m talking about the RESPONSE being self-contradictory.

If the app asks for 2 caps that can’t both be granted at the same time, why throw 7 instead of just…picking one or none? Isn’t a wallet allowed to grant any subset of the requested capabilities? If I were a wallet, I would simply reserve 7 for when it’s actually impossible, and pick my favorite of the two.

why throw 7 instead of just…picking one or none?

I prefer to fail safely and predictably I guess :rofl:

Maybe i don’t understand what you mean by incompatible. With each other?
If dapp requests “atomicBatch”:“true” && “atomicity”:“none”, are they contradictory? Or are they just expressing that, in YoavW’s words, atomicity is “a good to have” but not tactical?
Or if they request “atomicBatch”:“false” and “atomicity”:“strict”, are you saying the wallet should be forced by the spec to assume the request is malformed and drop it for safety’s sake? I feel like how all future capabilities will interact is hard to define in advance, and “contradiction” feels pretty hard to spec out here IMHO (not discouraging you from continuing to try, I’m just not seeing the logic yet)

I’m only suggesting that EIP-5792 pick an error code to use when the wallet refuses a request because of conflicting capabilities, regardless of what the capabilities are or why they are conflicting.

1 Like

Ah, OK, giving the wallet an optional way to express this specific fail-case would be great, I totally agree! I thought you were saying the wallet SHOULD or MUST return that error code if {hard-to-specify condition}.

I don’t see anything that maps to “contradictory/malformed-request” in the generic EIP-1193 error codes and in the CAIP-25 error codes 5000 is “unknown error” (at authorization-request level) and 5204 is “ambiguous/contradictory request” (having to do with overlapping CAIP-217 scope objects, i.e. CAIP-25-internal contradiction), which is probably the closest analogy to overlapping capability objects.

The new changes in the naming are welcomed, and good we took the atomicity comments from Sam into consideration. Having the capabilities in separate ERCs is also a step in the right direction.

One thing that is sorely missing from the specification, is a recommendation on the “atomicity”:
Trying to be “un-opinionated” on sending a batch leaves a lot of room for apps to hang themselves: e.g. an app sends a batch of 3 transactions through a “best effort” wallet, needs to handle all cases (that is, only 1, only 2, all 3) transaction succeeded - otherwise, the wallet can be left in limbo (or worse, in a vulnerable) state.

At a minimum, atomicity capability should be specified as SHOULD, while explaining the app has to understand and handle the consequences of sending a non-atomic batch.

wallet_sendCalls Example Return Value

The identifier can be any string. The only requirement is that for a given session, users should be able to call wallet_getCallsStatus with this value and expect a call-batch status to be returned.

The term “session” is not defined in the EIP and I don’t think there is a clear implied meaning. It would be great to provide more clarity on that.


Returning capabilities per chain id might be necessary, but in the case that a capability is globally supported for all chains, how is the wallet supposed to respond? Does it make sense to ask the wallet to enumerate all supported chains?

In the previous AllERCDevs call we discussed how this EIP opens an opportunity to solve a current UX pain point in Ethereum: the problem of displaying transaction parameters to users.

In eth_sendTransaction, the parameters are expressed as an opaque calldata bytestring. Ideally the wallet would show a detailed view of the transaction parameters the user is agreeing to, but there is no simple and robust way for wallets to decode calldata. One option is to rely on databases of function signatures, but function selectors are small and clashes are easy to find. Another option is to rely on verified source code and ABIs, but this currently depends on centralized providers, essentially on Etherscan. Function selector databases by extension also depend on those providers.

wallet_sendCalls has inherited the opaque data parameter. One idea that came up in the call was to specify the data for each call not as a bytestring but as a function ABI spec and the array of function arguments to be encoded by the wallet.

I think that would be very nice but is a relatively large departure from the current spec, which is currently already in Last Call, as well as a departure from eth_sendTransaction which might hinder adoption.

As an alternative, we could keep the EIP as is, with data as a bytestring, and use the capabilities mechanism to specify an ABI per target address so that the wallet can decode it. This is an improvement over the current state of things because the dapp already knows the ABI, it just needs to communicate it to the wallet.

A couple of things to note:

  • The mechanism should not be Solidity-specific. It should be possible to use different ABI formats and encoding/decoding procedures.
  • This mechanism would allow a dapp to provide a false ABI that could mislead a user as to what they’re signing. I’m not sure if this is a worse outcome than being shown opaque bytes. We may conclude that the wallet should check to see if the ABI has been verified, in which case we are back to relying on verification and the mechanism doesn’t really make sense. Curious to hear other’s opinions on this.
1 Like

From some discussion in All Wallet Devs today:

MetaMask is working towards an MIP to support regular JSON-RPC batching (non-atomic) for EIP 1193

2 Likes