aragon / connect Goto Github PK
View Code? Open in Web Editor NEW(Aragon 1) Seamlessly integrate DAO functionality into web and node.js apps.
Home Page: https://aragon.org/connect
License: GNU Lesser General Public License v3.0
(Aragon 1) Seamlessly integrate DAO functionality into web and node.js apps.
Home Page: https://aragon.org/connect
License: GNU Lesser General Public License v3.0
Having these values undefined
or null
on the subgraph cascade across the whole codebase. It would be nice low hanging fruit to do a quick review of the subgraph.
The current Connect API logic only calculates the shortest Forwarding Path. But in many cases, we may want more flexibility to allow:
ForwardingPathDeclaration
When we build the full version, it would be nice to tell it things like:
In practice all this is doing is allowing the user to narrow our search space for forwarding pathing.
In the current setup, we expect the user to know the subgraph specific URL of each network they are trying to connect.
For example:
const voting = new Voting(
votingInfo.address,
'https://api.thegraph.com/subgraphs/name/aragon/aragon-voting-mainnet'
)
It would be great to update current logic to default to a specific subgraph URL for each network using mainnet as default, as we are doing for the main connector. In this way, we will also encourage other devs working on their own app connectors to follow this convention.
The new way of connecting to the connector would be:
const voting = new Voting(
votingInfo.address,
{chainId: 4} //optional, default to 1
)
We should keep track of the final bundle size when the required modules are being imported in a web app.
We could have the following:
@aragon/connect
.@aragon/connect
+ app connector, for every core app.@aragon/connect
+ all the core app connectors.We could try to do this using https://bundlewatch.io/
Currently we only use the appId
in each app subgraph to determine a contract template.
However, an app instance may actually go through multiple versions (e.g. as they did when we upgraded 0.6 to 0.7 organizations), and this is ultimately in the control of the app developer and organization.
Ideally app subgraphs would be able to detect if an app changed its implementation address and switch to a different contract template which defines different event handlers. Technically we should be able to know when to do this if we also listen to all Kernel SetApp
events, but it's unclear how we would switch the template (outside of encoding a version in the entity and sprinkling if/else
s everywhere).
The documentation has a few features we have in our roadmap but that do not land to production yet. This is confusing for the current users of the library. For example the options.as
on the TransactionIntent
object.
We're currently in the process of migrating as much as possible of Apiary to The Graph and we'd like to use the subgraph already deployed for Aragon Connect. However, some metrics are missing, and I'd like to hear your thoughts on adding them:
See discussion #165 (comment)
Atm, our subgraphs need to use as script that reads an env variable with the access token. This shouldn't be necessary when graph auth
is fixed.
Submitted an issue in thegraph:
graphprotocol/graph-node#1714
This might be related to the changes in #203
In between polling updates, votes
return null
before being repopulated.
Here is an example from the react demo:
This causes jumps between loading and display at every interval.
Is this expected behaviour?
Subgraphs in voting and tokens are using a slightly more sophisticated data source system which hasn't been applied in the main subgraph.
E.g. compare manifest/templates in connect-thegraph
and connect-thegraph-tokens
. While the former just contains files at this point, the latter contains a contracts/
and a sources/
folder. The latter is the latest form of data source usage.
We may not want to have it conform to the others in this way, but it should at least be considered.
Try to answer the question: What is the content of Repo? It is quite common. We should include new method repoByName
that handle and parse a query in the lines of:
query {
repos(where: { name: $name }) {
id
name
lastVersion {
codeAddress
artifact
semanticVersion
}
}
}
Radspec descriptions are usually very organization-specific (contextual to each individual organization).
This would require aragon/radspec#88, but we should expose a way for Connect users to declare any additional radspec descriptions they'd like to incorporate into their organization's actions.
Another aspect I was thinking about was making the action descriptor transformation run-time configurable; an example might be an organization that is backed by a database (or IPFS blob) mapping descriptions to transaction hash or action id (e.g. voting app addr + vote id
).
Or “provider”.
"Can't resolve '@aragon/connect-react'" while running connect-react-intro
This issue goes further into the details of what it takes to create a Forwarding Path description. The logic that we currently support was migrated from aragon.js
and it's not flexible enough to provide lot of value for custom UI experiences.
To transition into a more powerful and descriptive data type as the one described in #132 we need to address a few tasks:
ForwardingPathDescription
will be constructed: https://github.com/aragon/connect/blob/master/packages/connect-core/src/utils/descriptions.ts#L14ForwardingPathDescription
: https://github.com/aragon/connect/blob/master/packages/connect-core/src/utils/path/decodePath.ts#L14I've been seeing a state update error when mounting a component that uses createAppHook
. It seems to occur only once when unmounting then remounting a component.
Below is an example I created by modifying the list-votes-react
demo, the only change is the addition of a button to control the display of the <Votes/>
component.
This issue is to keep track of:
Deploy Voting and Tokens app subgraphs to xDai.
Update app connectors configuration to support xDai as default.
We are not handling overloads correctly on ethers
. For examples:
await org.appIntent(Voting.address, 'newVote', ["0x00000001", "test"])
Error from ethers.js
with multiple matching functions
.
The source of problems is here.
It was reported that using the function signature
instead of the methodJsonDescription.name
fixed it.
This issue keep track of all the tasks that need to happen to refactor the Forwarding Path described on #132.
Transaction
: sign
, transactions
The current utilities list are: https://github.com/aragon/connect/blob/master/packages/connect-core/src/utils/index.ts
The boilerplate should help a new developer to bootstrap:
use-wallet
configuredThis is an advance provider that:
It uses a quorum and connects to multiple Providers as backends, each configured with a priority and a weight.
Ethers API documentation: FallbackProvider
The app()
and apps()
methods of Organization
could provide a way to filter the desired apps, by having a filtering object passed to them.
Proposed API:
// Selecting by appName
org.apps({ appName: 'voting.aragonpm.eth' })
// Selecting multiple appName
org.apps({ appName: ['voting.aragonpm.eth', 'token-manager.aragonpm.eth'] })
// Selecting by address
org.apps({ address: '0xcafe…' })
// Selecting multiple addresses
org.apps({ address: ['0xcafe…', '0xbeef…'] })
We could have other filters but address
and appName
would probably enough for now.
Selecting the first app that matches could be done this way:
const [voting] = await org.apps({ appName: 'voting.aragonpm.eth' })
Or by using .app()
, which should act as a convenient alias for the previous example:
const voting = await org.app({ appName: 'voting.aragonpm.eth' })
The only difference is that .app()
would also accept an address to be passed directly:
// these two lines are equivalent:
const voting = await org.app('0xcafe…')
const [voting] = await org.apps({ address: '0xcafe…' })
It will eventually make it possible to do this, for an org with a single voting app:
const voting = new Voting(await org.app({ appName: 'voting.aragonpm.eth' }))
Note: this is not the case yet, but we sould try to reuse the names and patterns we use for filters as much as possible so it feels consistent.
An “Aragon Button” builder that would allow to pick a certain action on an organization, and to export it as a single button ready to embed anywhere.
For example, a button could be configured to cast “Yes” on a specific vote of a given Voting app.
I think this is non-trivial for Connect, because it requires app-level information (and even then it may be difficult due to the lack of explicit information in events or other details).
Ideally, if you had an organization requiring a multi-step transaction path to execute an action, for example:
It would be ideal if a user could establish a link between an action going through the different steps, for example:
Approval#4
created Delay#5
Delay#5
created Vote#2
Vote#2
can be traced all the way back to Approval#4
(and any other intermediate steps as necessary)This would be useful for building UI that explains the path an action took, for example, to show all the steps taken (and to be taken) in one "proposal" detail view.
(If an action was at the middle Delay step, it would only be able to tell users that a potential vote may be created; see larger description)
The only way I know how to do this now is by inspecting the transaction that created a particular action (e.g. Vote#2
). You can eventually follow the logs to know that a particular Dispute#5
created the vote, but this is both slow and requires a lot of additional context. It would be much, much better if we could find a way to do this through a subgraph or another approach.
This issue will keep track of the planned changes regarding the intents, forwarding paths and transactions.
These changes are aiming to improve / solve the following:
[1] This is why the term “Forwarding Path” is now preferred to “Transaction Path”.
Going forward we'll use a milestone to keep track of the progress: https://github.com/aragon/connect/milestone/1
The idea here is to attach a default address to the connection context. This address will get used by the methods generating forwarding paths and transaction requests. It will be possible to override it at any point.
It could be passed to connect()
:
const myorg = await connect('myorg.aragonid.eth', 'thegraph', {
actAs: '0x…',
})
It should also be possible to update it without resetting the connection. A new method on Organization
could help doing that:
org.actAs('0x…')
ForwardingPath
AppIntent
and TransactionPath
.Organization
and App
(e.g. App#exec()
).new
).class ForwardingPath {
// A list of transaction requests ready to get signed.
transactions: Transaction[]
// Lets consumers pass a callback to sign any number of transactions.
// This is similar to calling transactions() and using a loop, but shorter.
// It returns the value returned by the library, usually a transaction receipt.
sign<Receipt>(
callback: (tx: Transaction) => Promise<Receipt>
): Promise<Receipt[]>
// Return a description of the forwarding path, to be rendered.
describe(): Promise<ForwardingPathDescription>
// Return a description of the forwarding path, as text.
// Shorthand for .describe().toString()
toString(): string
}
App
methods: exec()
and execPaths()
The two initial methods returning ForwardingPath
instances are App#exec()
(to get the shortest path) and App#execPaths()
(to get all the possible paths).
type ExecOptions = {
// The account to sign the transactions with. It is optional
// when `actAs` has been set with the connection. If not,
// the address has to be passed.
actAs: Address
// Optionally declare a forwarding path. When not specified,
// the shortest path is used instead.
path: ForwardingPathDeclaration
}
// No `path` option here since we want them all.
type ExecPathsOptions = {
actAs: Address
}
interface App {
exec(signature, params, options?: ExecOptions)
execPaths(signature, params, options?: ExecPathsOptions)
}
Address
This is a type we could use for documentation purposes.
type Address = string
AppOrAddress
This type accepts an App
instance or its address, and should get used whenever possible rather than an address only.
type AppOrAddress = App | Address
ForwardingPathDeclaration
This type allows to express a forwarding path in a simplified, but limited way: it is not possible to nest the forwarding actions.
type ForwardingPathDeclaration = AppOrAddress[]
Transaction
Transaction
replaces TransactionRequest
, and is now a type rather than a class. It describes a subset of the eth_sendTransaction
parameters in the Ethereum JSON-RPC API.
type Transaction = {
data: string
from: Address
to: Address
}
ForwardingPathDescription
This object contains all the information needed to render the description of a forwarding path. It gets returned by ForwardingPath#describe()
.
type ForwardingPathDescriptionTreeEntry =
| AppOrAddress
| [AppOrAddress, ForwardingPathDescriptionEntry[]]
type ForwardingPathDescriptionTree = ForwardingPathDescriptionEntry[]
class ForwardingPathDescription {
// Return a tree that can get used to render the path.
tree(): ForwardingPathDescriptionTree
// Renders the forwarding path description as text
toString(): string
// TBD: a utility that makes it easy to render the tree,
// e.g. as a nested list in HTML or React.
reduce(callback: Function): any
}
Paths can be complex and defining them using JS structures might not provide a level of clarity that is sufficient. Having a dedicated syntax could improve that.
Using tagged templates could make it possible to integrate our existing object types into it, App
and Intent
in particular.
Initial draft:
const p = path`
> ${voting}
> ?
> ${voting.createVote('something')}
> "encoded_sub_action_1"
> "encoded_sub_action_2"
> ${tokens}
> "encoded_action_1"
> "encoded_sub_action_1"
`
const txRequests = p.transactions({ as: '0x…' })
In this example, ?
would express a part that need to be filled by the library, if possible.
Note: this draft is only used to express the idea, its syntax will probably be different.
Using the language previously mentioned above, we could also provide a forwarding path builder. This tool would let users edit a forwarding path after its initial creation.
We could imagine an initial implementation accepting the same JS structure than the one returned by path\
``.
Initial draft:
const pathBuilder = path`
> ${voting}
> ?
> ${voting.createVote('something')}
> "encoded_sub_action_1"
> "encoded_sub_action_2"
> ${tokens}
> "encoded_action_1"
> "encoded_sub_action_1"
`
// Call insert() in this way to insert an action after "encoded_sub_action_2"
pathBuilder.insert('0 > 0', voting.createVote('something'))
// PathBuilder could inherit from Intent since it would provide the same methods:
pathBuilder.sign()
pathBuilder.transactions()
pathBuilder.path()
pathBuilder.paths()
Note: this draft is only used to express the idea, its syntax will probably be different.
I think it could be nice to consider the master
branch stable, and automate the build + version bump + npm publication using GitHub Actions.
We could:
change: major|minor|patch
) to determinate the new version.change:
information exists (and prevent merging without it).master
, a workflow would:
The changelog will still be edited manually.
Some things we might want to explore:
Some potential issues:
change: major|minor|patch
, which might cause issues.This would allow to publish on GitHub Packages, and just sync it with npm. It would make things easier if GitHub Packages provide a transparent bridge to npm at some point.
Like the signing panel we have on the client, this would allow app authors to provide to their users an easy way to pick a transaction path.
This issue keeps track of the changes that need to happen related to the Intent
entity described on #132.
Transaction
: sign
, transactions
path
method to use the new data structures and typespaths
This issue keeps track of the changes that need to happen to the Transaction
entity described on #132.
For use cases like Apiary it is necessary to have the timestamp at which an organization was created
This issue is to discuss and outline the scope of changes we may need to do to allow the app connector to add more details when sending transactions.
Brett's comment on the subject:
It's becoming clearer now, especially with Agreements and Disputable Voting, that app actions will have more context about the periphery transactions related to an action.
For example, in order to start a disputable vote (called directly or at the beginning of a transaction path), users will have to include one (or two) approval pre-transactions. And for the Agreement, a challenger could have up to four pre-transactions related to token approvals before they actually submit the transaction that starts the challenge.
Given this, I've started leaning more and more on allowing app connectors to include more logic on actions they expose, rather than directly mirroring
organization#appIntent()
.An alternative to this is providing a standard for app connectors to "hook" into an
appIntent()
call (e.g. "if I'm included in the forwarding chain, add a transaction"), but this would also force us to configure the app connectors in the mainconnect()
export.
Update the types to those described on #132
A
manifest.json
andartifact.json
comes from off-chain metadata published with each app's version, and I was thinking it'd be nice to encapsulate that information separately so it's more clear what comes from an on-chain source (and is thereby reliable) and what is from metadata (especially if we decide to version the metadata).
I'm unsure whether this should be a separate subgraph or not, but it would be super helpful to have organization names in the GraphQL API for things like Apiary.
My general feeling is that it is somewhat high cost to maintain, since the only way to get the organization names (as far as I know) is to decode transactions sent directly to one of the organization templates/kits, which inherently is a per-contract action. This would mean that a list would need to be maintained of the kits on each network, along with kit-specific handlers for attaching the names to the correct organizations.
Feedback from the hack.
Things that need to change from the tutorial:
import { Voting } from "@aragon/connect-thegraph-voting"
instead of using a default import.await org.app("voting").address
; doesn't seem to work anymore. Had to use:const apps = await org.apps();
const { address } = apps.find(app => app.appName.startsWith("voting."));
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.