Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
@onflow/fcl
Advanced tools
A high level abstraction (built on top of @onflow/sdk) that enables development of browser based dApps.
The things that exists probably won't be changing much externally, we will be adding new functionality in the near future.
npm install --save @onflow/fcl
Having trouble with something? Reach out to us on Discord, we are more than happy to help.
Last Updated: May 7th 2020
Follow this guide to understand the basics of how to build an app that interacts with the Flow blockchain using @onflow/fcl
This guide uses create-react-app
and does not require any server-side code. @onflow/fcl
is not tied to any front-end framework.
In this quickstart you will
@onflow/fcl
to perform authentication and authorization of Flow accounts@onflow/fcl
to send scripts and transactions to the Flow blockchain emulatorflow
)fcl-wallet
) to simulate connection between your app, @onflow/fcl
and a user's 3rd party key management software@onflow/fcl
for a production deploymentOnce complete, this example application will be deployable to the Flow test/main networks with only small changes to configuration values. Let's begin.
Run the following command to generate a React app. (Must have npm
installed)
npx create-react-app my-dapp
@onflow
DependenciesFrom the root directory of your new react app, run the following commands to install @onflow/fcl
and the @onflow/dev-wallet
npm install --save @onflow/fcl
npm install --save-dev @onflow/dev-wallet
@onflow/fcl
is the library we'll use to interact with the Flow blockchain.@onflow/dev-wallet
A "custodial" wallet that can authenticate and authorize transactions. It will simulate 3rd party key-management software necessary for interacting with the Flow blockchain on behalf of a specific Flow account.A Note on Wallets: Flow is designed to support most wallet types–– fully-custodial wallets, browser-based (extensions), hardware and other managed decentralized wallet options.
@onflow/fcl
uses a handshake protocol to enable wallets to manage Flow identities, and perform authentication and authorization. Any wallet that supports the protocol can be used by your users automatically without any configuration in the application.
In this guide, we'll use @emotion/styled
to write css. (You can skip this step, or install your own preferred css tools)
npm install --save @emotion/styled
The Flow emulator is a lightweight tool that emulates the behaviour of the real Flow network. The emulator comes bundled with the Flow CLI. Install the emulator by following these instructions.
From the root directory of your React app, run the following command to start the emulator
flow emulator start --init
Note: You don't need to use the --init
flag if you start the emulator from a directory that already contains the flow.json
file.
Running the above command starts the emulator and generates a flow.json
file similar to this
{
"accounts": {
"root": {
"address": "f8d6e0586b0a20c7",
"privateKey": "0ab0b3c92adf319ab118f6c073003f7029bb6fa8eb986f47f9b139fbb189e655",
"sigAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA3_256"
}
}
}
The emulated network is running and contains a single root account we can use to authorize transactions. We will connect the private key from this account to the dev-wallet
.
Create a scripts
entry in your package.json
with the following command. Copy and paste the private key from your root account in flow.json
and attach it to an environment variable named PK
{
"scripts": {
"dev:wallet": "SET PK=0ab0b3c92adf319ab118f6c073003f7029bb6fa8eb986f47f9b139fbb189e655 && fcl-wallet"
}
}
{
"scripts": {
"dev:wallet": "PK=0ab0b3c92adf319ab118f6c073003f7029bb6fa8eb986f47f9b139fbb189e655 fcl-wallet"
}
}
Use the new command to run the Dev Wallet
npm run dev:wallet
If all is well you should see
@onflow/dev-wallet@0.0.4
*** *** *** *** *** *** ***
🎉 FCL Dev Wallet has started:
* Origin: <http://localhost:8701>
* FCL Authn: <http://localhost:8701/flow/authenticate>
* GraphiQL: <http://localhost:8701/graphql>
* Access Node: <http://localhost:8080>
* Service Address: f8d6e0586b0a20c7
* Private Key: 0ab0b3c92adf319ab118f6c073003f7029bb6fa8eb986f47f9b139fbb189e655
Include this code in development to configure fcl:
import * as fcl from "@onflow/fcl"
fcl.config()
.put("challenge.handshake", "http://localhost:8701/flow/authenticate")
*** *** *** *** *** *** ***
We're ready to start building our new app. Start the React app to begin building the UI and interacting with the emulator using @onflow/fcl
npm start
Now that we have the Flow emulator, Dev Wallet and our React app up and running we're ready to build our application.
@onflow/fcl
Before we can use @onflow/fcl
to interact with Flow we'll need to tell it how to connect to the Dev Wallet we started earlier. Add the following code to src/App.js
import React from "react";
+ import * as fcl from "@onflow/fcl";
import logo from "./logo.svg";
import "./App.css";
+ fcl.config()
+ .put("challenge.handshake", "http://localhost:8701/flow/authenticate")
function App() {
// ...
}
@onflow/fcl
is now configured to connect to the Dev Wallet. For more information about how @onflow/fcl
interacts with Wallet providers, you can view documentation [../dev-wallet](dev wallet)
Once configured, all that is needed is to call fcl.authenticate()
in your code to authenticate Flow accounts.
Attach the fcl.authenticate
function to the onClick
handler of a button
<Button onClick={() => fcl.authenticate()}>Sign In/Up</Button>
To allow users to sign out of your application, simply call fcl.unauthenticate()
<Button onClick={() => fcl.unauthenticate()}>Sign Out</Button>
To receive a reactive update when a user has signed in/out you can subscribe to changes
fcl.currentUser().subscribe((user) => {
console.log(user)
})
Here is the code for the completed component containing the UI and logic for authenticating users using @onflow/fcl
. Add this code to CurrentUser.js
in the src
directory of your app
import React, {useState, useEffect} from "react"
import styled from "@emotion/styled"
import * as fcl from "@onflow/fcl"
const Root = styled.div``
const Img = styled.img`
width: 35px;
height: 35px;
`
const Name = styled.div``
const Button = styled.button``
const SignInButton = () => {
const [user, setUser] = useState(null)
useEffect(() => fcl.currentUser().subscribe(setUser), [])
if (user == null) return null
if (user.loggedIn) return null
return <Button onClick={fcl.authenticate}>Sign In/Up</Button>
}
const UserProfile = () => {
const [user, setUser] = useState(null)
useEffect(() => fcl.currentUser().subscribe(setUser), [])
if (user == null) return null
if (!user.loggedIn) return null
return (
<>
{user.identity.avatar && <Img src={user.identity.avatar} />}
<Name>{user.identity.name || "Anonymous"}</Name>
<Button onClick={fcl.unauthenticate}>Sign Out</Button>
</>
)
}
const CurrentUser = () => {
return (
<Root>
<SignInButton />
<UserProfile />
</Root>
)
}
export default CurrentUser
And display the CurrentUser
component in your app
+ import CurrentUser from "./CurrentUser"
fcl.config()
.put("challenge.handshake", "http://localhost:8701/flow/authenticate")
function App() {
return (
<div className="App">
+ <CurrentUser/>
</div>
)
}
Cadence scripts allow you to run computations on Flow that are not recorded on the blockchain. You'll mainly use scripts as a way of querying Flow for information about accounts and their resources. A script is not signed by any account and cannot modify an account's state.
Using a simple script is a useful way to test your connection to Flow
const resp = await fcl.send([
fcl.script`
pub fun main(): Int {
return 42 + 6
}
`,
])
const value = await fcl.decode(response)
// value === 48
To call A Cadence script from your React app, create another component and wire-up the UI. Here is an example component you can use. Create a file named ScriptOne
in the src
directory of your app with the following content
import React, {useState} from "react"
import styled from "@emotion/styled"
import * as fcl from "@onflow/fcl"
const Root = styled.div``
const Header = styled.div``
const Button = styled.button``
const Results = styled.pre``
export default function ScriptOne() {
const [data, setData] = useState(null)
const runScript = async (e) => {
e.preventDefault()
const response = await fcl.send([
fcl.script`
pub fun main(): Int {
return 42 + 6
}
`,
])
setData(await fcl.decode(response))
}
return (
<Root>
<Header>Script One</Header>
<Button onClick={runScript}>Run Script</Button>
{data && <Results>{JSON.stringify(data, null, 2)}</Results>}
</Root>
)
}
And display the component in your app
// ...
+ import ScriptOne from "./ScriptOne"
fcl.config()
.put("challenge.handshake", "http://localhost:8701/flow/authenticate")
function App() {
return (
<div className="App">
<CurrentUser/>
+ <ScriptOne/>
</div>
)
}
Go ahead and test out your new script!
A common use for Cadence scripts is to acquire information about a Flow account's public state and its resources. Here is an example of a script you might use to query and use another account's public resources.
const response = await fcl.send([
fcl.script`
import HelloWorld from 586b0d6e0a20c7f1
pub fun main() {
let helloAccount = getAccount(586b0d6e0a20c7f1)
let helloCapability = helloAccount.getCapability(/public/Hello)
let helloReference = helloCapability!.borrow<&HelloWorld.HelloAsset>()
log(helloReference?.hello())
}
`,
])
Cadence scripts can return complex Cadence data-types. These return values are sent over-the-wire to your JavaScript code. You'll handle parsing and transforming custom Cadence data-types using custom decoders.
Given this Cadence script that returns [SomeStruct(x: 1, y: 2), SomeStruct(x: 3, y: 4)]
const response = await fcl.send([
fcl.script`
pub struct SomeStruct {
pub var x: Int
pub var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
pub fun main(): [SomeStruct] {
return [SomeStruct(x: 1, y: 2), SomeStruct(x: 3, y: 4)]
}
`,
])
We would like to transform SomeStruct(x: 1, y: 2)
into a JavaScript data-structure.
class Point {
constructor({x, y}) {
this.x = x
this.y = y
}
}
Registering a decoding function using the code below will ensure that the response from fcl.send
will contain Point
objects wherever a SomeStruct
Cadence type is returned.
+ import Point from "./Point"
// ...
fcl.config()
.put("challenge.handshake", "http://localhost:8701/flow/authenticate")
+ .put("decoder.SomeStruct", data => new Point(data))
// ...
Here is a completed component that contains the script that will trigger our new decoding function. Create a file named ScriptTwo
in the src
directory of your app.
import React, {useState} from "react"
import styled from "@emotion/styled"
import * as fcl from "@onflow/fcl"
const Root = styled.div``
const Header = styled.div``
const Button = styled.button``
const Results = styled.pre``
export default function ScriptTwo() {
const [data, setData] = useState(null)
const runScript = async e => {
e.preventDefault()
const response = await fcl.send([
fcl.script`
pub struct SomeStruct {
pub var x: Int
pub var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
pub fun main(): [SomeStruct] {
return [SomeStruct(x: 1, y: 2), SomeStruct(x: 3, y: 4)]
}
`,
])
setData(await fcl.decode(response))
}
return (
<Root>
<Header>Script Two</Header>
<Button onClick={runScript}>Run Script</Button>
{data && <Results>{JSON.stringify(data, null, 2)}</Results>}
<span>{data && data !== null && data[0].constructor.name} 1 </span> <!-- "Point 1" -->
<span>{data && data !== null && data[1].constructor.name} 2 </span> <!-- "Point 2" -->
</Root>
)
}
Display the ScriptTwo
component in your app
// ...
import CurrentUser from "./CurrentUser"
import ScriptOne from "./ScriptOne"
import ScriptTwo from "./ScriptTwo"
// ...
function App() {
return (
<div className="App">
<CurrentUser/>
<ScriptOne/>
+ <ScriptTwo/>
</div>
)
}
Flow Transactions are used to move resources and interact with smart contracts on behalf of Flow accounts. @onflow
provides flexible primitives composing authorizing and paying for Transactions on Flow.
@onflow
allows for specifying the payer, proposer and authorizer of transactions on Flow.
Describing the specifics of how to compose Flow transactions is beyond the scope of this guide. For more information about how to build Flow transactions you can read the docs here.
To send a transaction you must supply a payer and proposer. In the following transaction the current user we authenticated earlier is used for each. @onflow/fcl
will use the configured wallet to sign this transaction on behalf of the current user.
const response = await fcl.send([
fcl.transaction`
transaction {
execute {
log("A transaction happened")
}
}
`,
fcl.proposer(fcl.currentUser().authorization),
fcl.payer(fcl.currentUser().authorization),
])
You can subscribe to the result of a transaction in your client code.
const unsub = fcl.tx(response).subscribe((transaction) => {
if (fcl.tx.isSealed(transaction)) {
setState("Transaction Confirmed: Is Sealed")
unsub()
}
})
Here is a completed component that contains the transaction above. Create a file named TransactionOne
in the src
directory of your app.
import React, {useState, useEffect} from "react"
import styled from "@emotion/styled"
import * as fcl from "@onflow/fcl"
const Root = styled.div``
const Button = styled.button``
const Status = styled.pre``
export default function TransactionOne() {
const [status, setStatus] = useState("Not Started")
const runTransaction = async (e) => {
e.preventDefault()
setStatus("Resolving...")
const response = await fcl.send([
fcl.transaction`
transaction {
execute {
log("A transaction happened")
}
}
`,
fcl.proposer(fcl.currentUser().authorization),
fcl.payer(fcl.currentUser().authorization),
])
setStatus("Transaction Sent, Waiting for Confirmation")
const unsub = fcl.tx(response).subscribe((transaction) => {
if (fcl.tx.isSealed(transaction)) {
setStatus("Transaction Confirmed: Is Sealed")
unsub()
}
})
}
return (
<Root>
<Button onClick={runTransaction}>Run Transaction</Button>
<Status>{status}</Status>
</Root>
)
}
Display the TransactionOne
component in your app
// ...
import CurrentUser from "./CurrentUser"
import ScriptOne from "./ScriptOne"
import ScriptTwo from "./ScriptTwo"
+ import TransactionOne from "./Transaction"
// ...
function App() {
return (
<div className="App">
<CurrentUser/>
<ScriptOne/>
<ScriptTwo/>
+ <TransactionOne/>
</div>
)
}
Our application is complete!
To deploy your app, you'll need to modify your configuration. Once the Flow Mainnet is live you'll be able to obtain an production Access Node API url and API Key. More on this soon!
if (process.env.NODE_ENV === "development") {
fcl
.config()
.put("challenge.handshake", "http://localhost:8701/flow/authenticate")
}
if (process.env.NODE_ENV === "production") {
fcl
.config()
.put("accessNode.api", process.env.ACCESS_NODE_API)
.put("accessNode.key", process.env.ACCESS_NODE_KEY)
}
Congratulations you've completed a tour of the basic functionality of @onflow/fcl
by completing the following tasks
@onflow/fcl
to perform authentication and authorization of Flow accounts@onflow/fcl
to send scripts and transactions to the Flow blockchain emulatorflow
)fcl-wallet
) to simulate connection between your app, @onflow/fcl
and a user's 3rd party key management software@onflow/fcl
for a production deploymentHopefully this give you a head start developing your idea on Flow! Thanks for reading.
FAQs
Flow Client Library
The npm package @onflow/fcl receives a total of 16,113 weekly downloads. As such, @onflow/fcl popularity was classified as popular.
We found that @onflow/fcl demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.