EIP-5792 - Wallet Function Call API

Can you share an example of when you’d be ok with loose or no atomicity even though you wanted strict?

This case sounds like it’s not known by the dapp whether atomicity is needed or not, but that’s a really advanced user and the user should specify the atomicity requirement in this case… but wouldn’t they just not send these transactions separately if their wallet doesn’t support it or do some other workaround? Seems like a slightly convoluted use case AFAICT

The most concrete use case that came to mind was a block explorer with a transaction queue. If it provides users visiting with a way to visit a few contracts and build a set of transactions to execute, a naive user would probably expect the batch to execute together, especially with only one wallet signature for the full queue, and so the default behavior should be strict atomicity.

I agree that the ‘loose’ atomicity is a rather weak construction, as it encourages users to route batches to private mempools, and feels like an abstraction leak that may change with underlying things like AUTH/AUTHCALL or single-slot finality. I’d be happy to hear more arguments in it’s favor, but having a bollean flag for enforcing all-or-nothing execution of a bundle seems like a good abstraction of underlying wallet mechanics for developers of tools like block explorers or general purpose contract interfaces.

I’m operating under the assumption that as the EVM gets used by more people, competent early adopters will continue using EOAs, but new/less advanced users will onboard to accounts with features like atomic batching. I think we should make it easy for dapps to cater to them, and warn EOA users that “the bundle may only succeed in part or be split up, would you like to send the transactions anyway”.

Essentially I’d like the line in the EIP

MAY revert all calls if any call fails

to instead be

MUST revert all calls if any call fails when "atomic": "true"

1 Like

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.

This EIP is stagnant, is there anything wrong?

I’ve been working on atomic:

Maybe I can help you

1 Like

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?