Showing Pending (Forwarded) Actions in Apps

From discussions with @Quazia and @Paty, amongst others.

If you’d like, you can skip to the initial API mock below (see “Path forward”).



  • Immediate forwarders: those that automatically forward their actions, pending immediate checks (e.g. the Token Manager immediately executes actions if the sender holds the associated token)
  • Interactive forwarders: those that require interaction for an action to pass (e.g. the Voting app only executes actions if the associated vote passes)

Another way to categorize these two types is to use timing terminology:

  • Immediate forwarders are synchronous
  • Interactive forwarders are asynchronous.

Status quo in the Aragon client

Users lack any in-app feedback regarding forwarded actions.

They go to an app, decide on an action, and sign a transaction (containing that action’s intent) that eventually gets mined. Afterwards they’re left in the dark, because they’ve received no feedback about what happened after and if they need to do anything (unless the intent was synchronously successful, e.g. the sender was the only possible voter in the entire organization).

Although their original action intent is encoded in the transaction they signed, this intent may require any number of prior steps before it can finally be executed on the “target” app (e.g. Token Manager -> Voting -> Finance).

For clarity, let’s step through an example flow using a 2-of-2 multisig organization* on the current 0.6 client:

  • I go to the Finance app, and want to transfer out 100 DAI for an Aragon hoodie (the action intent)
  • I enter the required details in the “Withdraw” panel
  • The signing panel opens, informing me of the steps my action intent will take
  • I sign the transaction
  • …
  • Wait; browse some other Aragon merch to keep busy
  • Some time afterwards, my signing provider tells me my transaction was mined
  • But nothing’s changed in the UI! Whut am I gonna dooo??
  • …
  • Realize the Token Manager is the address I sent the transaction to (as it was the initial forward), so I go to its UI
  • Ain’t nothing here about my DAI transfer!
  • …
  • Remember the signing panel told me it would go through the Voting app afterwards, so I go to its UI
  • See my transfer intent in a vote
  • Vote “yes”
  • Bug other multisig owner to vote yes
  • …
  • If the other multisig owner votes yes, the transfer is complete and shows up in the Finance app’s UI

* Note: the default permissions of a 2-of-2 multisig organization require all actions to pass through a vote, and only token holders can create votes

Problem Areas

Any action not directly executed against an app’s contract (which will be almost all actions in a typical organization) is untraceable for the user, unless they have strong knowledge of how the organization is set up and what each app’s UI is meant to show.

There is no immediate feedback in the final (“target”) app’s UI when you invoke an action that requires an interactive forwarder.

The upcoming transactions activity panel in 0.7 will show which app you’ve sent a transaction to, but for default organizations this will almost always be the Token Manager because it’s the initial forwarder (for the token holder check).

Technical excuses for poor UX

Getting the required on-chain information to ascertain the status of any particular action is time and resource intensive if we do it naively.

Technically, with a built-in DB or intermediate caching layer, we could process all Ethereum blocks, scan all transactions, and build up a model of the organization where we knew everything about it.

Realistically, this is impossible to do in a way to that would be usable for users. Our client would feel like Augur’s, where it’d take days to initially sync. In the future more intermediate caching layers will be necessary, but until then, we’re trying to sync as much as we can off of the chain directly.

Path forward

We can help the client understand more about an organization and its apps’ pending actions by providing API hooks. On some level, the idea is to “cheat” the information barrier by asking apps to provide the relevant information.


Apps will need an API (in aragonAPI) to both receive and send information about pending actions. However, the “sender” side API is only intended to be used by forwarders.

Sender API

Used by forwarders—apps implementing the IForwarder interface.

On receiving a pending action (most likely an EVMScript), send information back to the Aragon client with:

  • An ID (e.g. voteId)
  • The “target” action, including address and calldata (would require decoding and unwrapping EVMScripts)
  • (Perhaps optional) The execution path left (would require decoding and unwrapping EVMScripts)

The Aragon client could then take this information, register it based on the app that sent it, and notify the “target” app (by using the address) about the pending action.

The ID is important to allow the forwarder to “deregister” pending actions once its been executed, to allow the “target” app to stop showing the pending action (either it will appear directly in the “target” app’s UI, or it’s the next forwarder’s responsibility to register the action again).

Note: This is primarily intended to be used by interactive forwarders, as I find it pointless for immediate forwarders. However, you could still use it in immediate forwarders, and could receive this information in the frontend by emitting an event in the forward() function.

Receiver API

Most apps should use this.

A simple observable API that emits an array of pending actions and where they were registered from. Apps shouldn’t be too confident about these actions actually executing, as they may never reach their final target (e.g. failed votes).

In the example flow above, this would allow the Finance app to immediately display a “Transfer” pending action in its UI after the transaction was mined, as well as where it was stuck at the moment (Voting). The calldata could be parsed to know the function call and render more useful information to a user.

Note: this will likely be accompanied by a recommended UX pattern implemented in each of the default Aragon apps (Finance, Token Manager, Voting).

Metadata declaration

It may also help the Aragon client render information if apps declared what type of forwarding interface they expect. In particular, it is more important for the client to know (and therefore help users with) interactive forwarders than immediate forwarders.

We could add a simple flag to an app’s arapp.json for advertising its forwarding type.


This API pushes the implementation responsibility to individual forwarding apps. Apps that don’t correctly implement these APIs would effectively behave similarly to today, where pending actions become “lost”.