onflow / fcl-js Goto Github PK
View Code? Open in Web Editor NEWFCL (Flow Client Library) - The best tool for building JavaScript (browser & NodeJS) applications on Flow ๐
Home Page: https://onflow.org
License: Apache License 2.0
FCL (Flow Client Library) - The best tool for building JavaScript (browser & NodeJS) applications on Flow ๐
Home Page: https://onflow.org
License: Apache License 2.0
We have landed on a concept we call Authorization Functions
as a standardized way to sign transactions. We need some documentation and specs outlining their role to play, what they are, how they work, what they need to do, what they are passed and what they need to return.
Documentation
Spec
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Context:
Remove dependency on big number
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
As more people onboard and get started building their next-gen apps on Flow, having great documentation surrounding the use of the JS-SDK Types will empower developers to get started building their apps fast. Currently there isn't sufficient documentation and examples surrounding using the JS-SDK Types, and developers are experiencing some friction when getting started. Since Flow is designed to be the go-to blockchain for empowering developers, the JS-SDK Types must meet and exceed this standard by providing best in class documentation and examples.
As more people onboard and get started building their next-gen apps on Flow, having great documentation surrounding the use of the JS-SDK will empower developers to get started building their apps fast. Currently there isn't sufficient documentation and examples surrounding using the JS-SDK, and developers are experiencing some friction when getting started. Since Flow is designed to be the go-to blockchain for empowering developers, the JS-SDK must meet and exceed this standard by providing best in class documentation and examples.
For a guide on how to use the SDK Start Here
Not sure what the link was to display, so I can't suggest a solution.
A key part of the usability of the Flow JS-SDK will be in being able to quickly identify and remedy errors that occur during development. Since errors can naturally occur anywhere in the codebase, common errors that can come up in each of those parts of the codebase must be identified and tracked. Since common errors will likely require the same solution to fixed, those solutions to those common errors should be also tracked.
An ERRORS.md
document should be created in each module to list each common error and its corresponding solution. A UID (Unique identifier) must be generated for each error and solution, and should accompany each error and solution in each ERRORS.md
document.
Future work to the JS-SDK will be to implement code to catch these common errors, and throw a new error with an accompanying link to the right part of the ERRORS.md document stored in this repo. The developer receiving these errors will be able to identify which common error they are seeing, and using the UID for that error, they can find the corresponding solution to that error.
ERRORS.md
document is included in each module in this repository.ERRORS.md
documents.Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Context:
Need to break down modules into smaller single purpose better documented modules with types.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Moving resolvers out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Currently when user sends a transaction, FCL gathers signatures from wallet provider and then calls access node gRPC by itself. In this case, wallet provider wouldn't necessarily know the status of the TX, or if it's sent to blockchain at all (maybe user gets disconnected from internet after wallet signs the TX).
Wallet provider doesn't necessarily know the status of the TX after it has been signed.
https://github.com/onflow/flow-js-sdk/blob/master/packages/send/src/send-transaction.js#L47
As custodial wallet provider serving also as payer, we would need to keep track of the status of the TX.
An alternative solution is to notify wallet provider the TX ID so wallet provider can track itself, which seems a bit ugly IMO.
Need to go through the current FCL documentation and make sure everything is updated to the latest and greatest.
Stored Interactions encapsulate common use cases of the Flow JS-SDK. Instead of building an entire interaction yourself, you can choose to use a stored interaction which will accomplish your desired outcome for you. Currently, there exists no documentation for any stored interaction in the JS-SDK. In order to provide a better experience for our developers, documentation must be created to better explain the purpose of stored interactions and each stored interaction that is created.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
We want our artifacts to be as consumable as possible on as many platforms as possible. Currently our modules only allow for the consumption by platforms and build tools that support CommonJS. As we start to break down our larger modules into smaller more composable modules, it should be a good time to start supporting more things. We are in need of some sort of documentation on how to construct our modules in a way that can support as many platforms as reasonably possible at this time.
Documentation contains instructions that enable the use of the module with the following platforms
Right now this is going to be an extremely manual process, as no build tools realistically produce the sort of outcome we are wanting here, in particular around Browser-ESM and Deno support.
The CRUD style Get/Put/Update/Destroy functions available in the current interaction package must be removed as to allow for greater decoupling of packages and overall better code health.
Currently the authorization logic is exactly the same when user identity is used as a proposer and payer
fcl.proposer(fcl.currentUser().authorization)
fcl.payer(fcl.currentUser().authorization)
And they will be merged into a single authorization request and will only get a single signature.
For some wallet providers this may need to be different when an identity is used as proposer and when it's used as payer. For example, a custodial wallet provider may use the same payer account for all of its users.
Accept configuration from handshake hook so proposer and payer logic can be different.
Augment the hook API spec to specify different address when the identity is used as a payer
{
addr: '0000000000000000000000000000000000000002',
keyId: 0,
// Add this. When payerAddr is not present then use addr as payerAddr.
payerAddr: '0000000000000000000000000000000000000003',
identity: {},
...,
},
Then perhaps in interactions
handle makePayer
and makeProposer
differently
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
The interaction adt has a tag field that uses a binary representation of the different types of interactions it can be. We originally did this for performance, but now it seems that was a little premature. The idea here is to pull these individual tags out into their own modules, so other modules in the future can depend on them in the future without requiring the entire interaction module. We also want to add and remove tags in the future, and needing to update everything that consumes a tag because we added somethings that has nothing to do with it seems like a hassle and a burden we don't want to push on the consumers of things, so they should be in separate modules.
@onflow/ix-tag-get-account
exists and is consumed by interaction@onflow/ix-tag-get-events
exists and is consumed by interaction@onflow/ix-tag-get-latest-block
exists and is consumed by interaction@onflow/ix-tag-get-transaction-status
exists and is consumed by interaction@onflow/ix-tag-ping
exists and is consumed by interaction@onflow/ix-tag-script
exists and is consumed by interaction@onflow/ix-tag-transaction
exists and is consumed by interactionMoving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
An upcoming change to the Flow Access API will require a network tag to be prepended to each signed data as it is sent to the Access API. This network tag will determine whether the data is valid for the specified network it is to be sent to. Signing functions must consume a tag
variable in their interface as to determine if the data it is to sign is being signed for the correct network it is intended for. If, for example, a piece of data is to be signed without necessarily being sent to a network (ie: without a network tag), a standardized method is needed as to construct the correct call to a signing function for this case.
A new sdk.sign
function available in the Flow JS-SDK will allow arbitrary pieces of data to be signed without specifying a network tag.
sdk.sign
will contain an implemenatation potentially like:
async function sign(authorization, data) {
const acct = await authorization(account())
return acct.signingFunction({
message: data,
tag: "ARBITRARY",
addr: acct.addr,
keyId: acct.keyId,
roles: {
proposer: false,
payer: false,
authorizer: false,
},
interaction: null,
})
}
This implementation proxies the call to sdk.sign
to the signing function available on the account derived from the authorization passed into it. The tag ARBITRARY
will allow the signing function to determine that this data to be signed is not intended to have a network tag prepended to it.
sdk.sign
which can sign arbitrary data.FCL is changing, we have plans for bringing profiles back later, but that will be in a fairly different way (FCL Profile Services).
In order to safeguard against developers using something that will be going away we should bring the dev-wallet as close to what it will be as we can, in this case it should mostly be removing functionality from the dev-wallet.
Need a blog or forum post to document what the current state of FCL.
-What we have
-Where we are going
-Where we need help
If the FCL (using dev-wallet) is used on a host page running with https
, then calls to the access node also use https
, despite FCL being configured with http
.
For example, dapper-web-services
runs on localhost using https
. It uses the FCL/dev-wallet and the FLOW emulator running locally to allow a user to pay for purchases using Flow tokens. FCL is configured as:
fcl
.config()
.put('accessNode.api', 'http://localhost:8080')
.put('challenge.handshake', 'http://localhost:8701/flow/authenticate');
When the user attempts to pay for something with their Flow tokens, we call FCL:
const authorization = fcl.currentUser().authorization;
const transaction = await fcl.serialize([
fcl.payer(authorization),
fcl.proposer(authorization),
fcl.authorizations([authorization]),
fcl.transaction`${cadenceTx}`,
]);
which pops open the dev-wallet iframe:
The iframe makes requests to the challenge.handshake
url on http
as expected by the configuration above.
However, when the user clicks "Use this profile", FCL will attempt to make a request to the accessNode.api
on https
, not http
as specified in the configuration:
From what I've seen from tracing through the running code, the url //localhost:8080/access.AccessAPI/GetAccount
is passed to fetch
, and since the request is coming from the host app (ie. dapper-web-services
running on https
), it uses https
as the scheme instead of http
.
Try to use the dev wallet + flow emulator on an app that is using https
instead of http
.
This is blocking a "Pay with Flow tokens" POC on dapper-web-services
. The POC would allow a user to buy NBA Top Shot moments using Flow tokens when running the Dapper app locally.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
We are trying to create a centralized location for configuration, for both the SDK and FCL. One of the reasons for this is so that we can have a version of sdk.send
that can find the accessNode from a centralized application level configuration.
@onflow/sdk-config
exists and conforms to module standards@onflow/fcl
uses @onflow/sdk-config
instead of packages/fcl/src/config/
Moving resolvers out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Transactions currently only contain the absolute minimum amount of data needed for signingFunctions to sign, verify and recreate them.
Currently the data we send to a signingFunction looks like this:
type Interaction {
// the entire interaction used for reconstruction
}
type Roles {
proposer: Boolean
payer: Boolean
authorizer: Boolean
}
type payload {
message: Hex
addr: String
roles: Roles
interaction: Interaction
}
This isn't exactly what it should be, but a very quick first pass could add something like this:
type Image {
src: String
alt: String
width: Number
height: Number
}
type Meta {
title: String
description: String
image: Image
}
type Payload {
...
meta: Meta
}
Really it only needs to be enough to enable wallets to make the experience a little better.
Using the rest of the sdk as an example it could look something like this:
sdk.build([
sdk.transaction(TRANSFER_NFT),
sdk.title("Title of NFT"),
sdk.description("Its the best NFT"),
sdk.image("https://placekitten.com/g/200/200", {
width: 200,
height: 200,
alt: "An adorable NFT"
})
])
// -- or --
sdk.build([
sdk.transaction(TRANSFER_NFT),
sdk.meta([
sdk.title("Title of NFT"),
sdk.description("Its the best NFT"),
sdk.image("https://placekitten.com/g/200/200", {
width: 200,
height: 200,
alt: "An adorable NFT"
})
])
])
Add the ability to optionally send along to the signingFunction
the following meta data
Types of meta data values are checked
type Image
from above)Documentation that outlines how to set the following meta data
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
The concept of FCL and the role it plays in the bigger picture of things has changed drastically over the last couple months. Before we had a lot of trouble explaining to people the difference between the SDK and FCL, but now I think those dividing lines are much clearer. I think we are now in need of a document that sort of explains where we are, where we are going, and our plan to get there.
Document needs to outline the following
fcl.currentUser().subscribe()
and fcl.currentUser().snapshot()
are used to access the current state of the user. FCL will be moving in a slightly different direction, these functions will still be usable to know the status of the currentUser
such as if they are authenticated or not, but we have now discovered this shouldn't be the home of other things like the current users profile. Because of our commitment to backwards compatibility we will be deprecating access to individual fields on the object, and removing them in a later issue. This issue is only about making consumers of the functions aware that certain fields they are using should not be used anymore.
The current data structure fcl.currentUser().subscribe()
and fcl.currentUser().snapshot()
return look like this:
type Identity {
name: String
addr: String
avatar: String
cover: String
color: String
bio: String
}
type Scope {
email: String
}
type Provider {
addr: String
pid: String
name: String
icon: String
}
type Authorization {
// Will eventually be replaced with fcl authorization services
}
type CurrentUser {
cid: String
loggedIn: Boolean
verified: Boolean
identity: Identity
scoped: Scope
provider: Provider
authorizations: [Authorization]
}
For now the only things we have confidence in keeping around are:
type CurrentUser {
cid: String // Who is currently authenticated
loggedIn: Boolean // Are they authenticated
authorizations: [Authorization] // This is still needed for fcl to work, will be deprecated later
}
Documentation on the deprecation of the available values
Let consumer of fcl know when they access one of the deprecated values including a link to the docs.
We need a module which exposes a single function which can generate a string which is extremely unlikely to be generated again - a unique identifier.
This unique identifier will be used to generate ids used in the interaction ADT.
As more people onboard and get started building their next-gen apps on Flow, having great documentation surrounding the use of the JS-SDK will empower developers to get started building their apps fast. Currently there isn't sufficient documentation and examples surrounding using the JS-SDK, and developers are experiencing some friction when getting started. Since Flow is designed to be the go-to blockchain for empowering developers, the JS-SDK must meet and exceed this standard by providing best in class documentation and examples.
We are wanting to remove the current param mechanism from the sdk. Due to our commitment to backwards compatibility, this issue is mostly about adding deprecation warnings when params are used and how to migrate away from them.
Currently we can write a script like this using params:
function add(a, b, message) {
return fcl.send([
fcl.script`
pub fun main(): Int {
log("${p => p.msg}")
return ${p => p.a} + ${p => p.b}
}
`,
fcl.params([
fcl.param(a, t.Identity, "a"),
fcl.param(b, t.Identity, "b"),
fcl.param(message, t.Identity, "msg")
])
])
}
add(5, 6)
.then(fcl.decode)
.then(value => assert(value === 5 + 6)) // true
Originally we were hoping to gracefully transition this into the arguments (which were recently added), thinking that people would only need injection style interop or interaction level arguments, but this line of thought proved to be incorrect. We now understand that what the consumer needs is arguments for user input to scripts and transactions, and being able to dynamically change the script/transaction given some sort of external value that is completely in control of the consumer, all of which we can already do.
Injection style interop (params) is also quite tricky. It is susceptible to injection attacks (where the value escapes the current expression, does its own malicious expression, continues on as if nothing happend), the user is responsible for making sure the cadence is valid. For example: log(${p => p.imAString})
would break because the string isn't wrapped in quotes and would have to be written like: log("${p => p.imAString}")
, a subtle but devastating issue if missed.
Also the code example above can be done a couple other ways.
First as arguments (the preferred way) which has the following benefits
function add(a, b, message) {
return fcl.send([
fcl.script`
pub fun main(a: Int, b: Int): Int {
return a + b
}
`,
fcl.args([
fcl.arg(a, t.Int),
fcl.arg(b, t.Int),
])
])
}
// original assert should still hold true
As standard string interop. This has many of the original issues with params, but it is way less complex, closer to what people understand as standard javascript, and is more obvious that the users are responsible for making sure the values once injected into the cadence is valid. (I think its also easier to read and understand the intent than the params)
function add(a, b, message) {
return fcl.send([
fcl.script`
pub fun main(): Int {
log("${message}")
return ${a} + ${b}
}
`
])
}
// original assert should still hold true
As a mix of the above.
The case for this one would be where the message
is in control of the dapp (consumer) while the user of the dapp is in control of a
and b
. Pros and Cons of the above two examples also apply to this one.
function add(a, b, message) {
return fcl.send([
fcl.script`
pub fun main(a: Int, b: Int): Int {
log("${message}")
return a + b
}
`,
fcl.args([
fcl.arg(a, t.Int),
fcl.arg(b, t.Int),
])
])
}
Transition documentation
Display deprecation notices with transition documentation when
fcl.params
is called${p => p.a}
Documentation on when to use arguments vs standard interop
The original design of the encode package for the Flow JS-SDK introduced a unique interface to pass in arguments to be encoded. A more robust solution would be to update the interface of the encode package to more closely reflect the structure of the interaction ADT that flows through the entire JS-SDK.
The encode package should expose two functions with the following signatures:
const rlpEncodedInsideMessage = encodeInsideMessage({
...ix.message,
proposer: ix.accounts[ix.proposer],
payer: ix.accounts[ix.payer].addr,
authorizers: ix.authorizers.map(cid => ix.accounts[cid].addr)
})
const rlpEncodedOutsideMessage =encodeOutsideMessage({
...ix.message,
proposer: ix.accounts[ix.proposer],
payer: ix.accounts[ix.payer].addr,
authorizers: ix.authorizers.map(cid => ix.accounts[cid].addr),
payloadSigs: insideSignatures,
})
encodeInsideMessage
and encodeOutsideMessage
.encodeInsideMessage
and encodeOutsideMessage
have signatures that reflect the above.In order to improve the usability of the Flow JS-SDK, better, in depth documentation is required for the Interaction ADT which is used throughout the codebase.
The interaction adt has a status field that uses a binary representation of the different types statuses it can have. We originally did this for performance, but now it seems that was a little premature. The idea here is to pull these individual statuses out into their own modules, so other modules in the future can depend on them in the future without requiring the entire interaction module. We also want to add and remove statuses in the future, and needing to update everything that consumes a status because we added something that has nothing to do with it seems like a hassle and a burden we don't want to push on the consumers of things, so they should be in separate modules.
@onflow/ix-status-ok
exists and is consumed by @onflow/interaction
@onflow/ix-status-bad
exists and is consumed by @onflow/interaction
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
As more people onboard and get started building their next-gen apps on Flow, having great documentation surrounding the use of the JS-SDK Send package will empower developers to get started building their apps fast. Currently there isn't sufficient documentation and examples surrounding using the JS-SDK Send package, and developers are experiencing some friction when getting started. Since Flow is designed to be the go-to blockchain for empowering developers, the JS-SDK Send package must meet and exceed this standard by providing best in class documentation and examples.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
Actor is a mechanism in FCL that helps eliminate certain race conditions, allowing for async communication between two entities but still allowing for a forced order where it matters. In the future we want to be able to pull fcl.config
out into its own module so the SDK can be more usable, fcl.config
depends on Actor so this issue is also a prerequisite for this.
@onflow/actor
module exists and conforms to the module standards@onflow/fcl
uses @onflow/actor
in place of packages/fcl/src/actor
A common use case for the Flow JS SDK is to set the code for an Account on Flow. In Flow, Accounts contain a string of Cadence Code within them, and a transaction is required to set the code within that account. Having a stored interaction for setting an accounts code will be valuable in that developers will not need to build their own solutions for what is a common use case.
The Set Code on Account Stored Interaction must follow the same format as the stored interaction for creating an account which already exists in the repo.
Moving builders out of the SDK package into their own single purpose package will enable better code health, smaller bundle size and generally decrease entropy between packages when things inevitably change and progress.
https://github.com/onflow/flow-js-sdk/blob/master/packages/dev-wallet/server/domains/user.js#L8-L18
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.