Skip to main content

Flow Dev Wallet

The Flow Dev Wallet is a mock Flow wallet that simulates the protocols used by FCL to interact with the Flow blockchain on behalf of simulated user accounts.

IMPORTANT

This project implements an FCL compatible interface, but should not be used as a reference for building a production grade wallet.

This project should only be used in aid of local development against a locally run instance of the Flow blockchain like the Flow emulator, and should never be used in conjunction with Flow Mainnet, Testnet, or any other instances of Flow.

info

To see a full list of Flow compatible wallets visit Wallets page

Getting Started​

Before using the dev wallet, you'll need to start the Flow emulator.

Install the flow-cli​

The Flow emulator is bundled with the Flow CLI. Instructions for installing the CLI can be found here: flow-cli/install/

Create a flow.json file​

Run this command to create flow.json file (typically in your project's root directory):


_10
flow init

Start the Emulator​

Start the Emulator and deploy the contracts by running the following command from the directory containing flow.json in your project:


_10
flow emulator start
_10
flow project deploy --network emulator

Configuring Your JavaScript Application​

The Flow Dev Wallet is designed to be used with @onflow/fcl version 1.0.0 or higher. The FCL package can be installed with: npm install @onflow/fcl or yarn add @onflow/fcl.

To use the dev wallet, configure FCL to point to the address of a locally running Flow emulator and the dev wallet endpoint.


_10
import * as fcl from "@onflow/fcl"
_10
_10
fcl
_10
.config()
_10
// Point App at Emulator REST API
_10
.put("accessNode.api", "http://localhost:8888")
_10
// Point FCL at dev-wallet (default port)
_10
.put("discovery.wallet", "http://localhost:8701/fcl/authn")

info

For a full example refer to Authenticate using FCL snippet

Test harness​

It's easy to use this FCL harness app as a barebones app to interact with the dev-wallet during development:

Navigate to http://localhost:8701/harness

Wallet Discovery​

Wallet Discovery offers a convenient modal and mechanism to authenticate users and connects to all wallets available in the Flow ecosystem.

The following code from Emerald Academy can be added to your React app to enable Wallet Discovery:


_55
import { config, authenticate, unauthenticate, currentUser } from "@onflow/fcl";
_55
import { useEffect, useState } from "react";
_55
_55
const fclConfigInfo = {
_55
emulator: {
_55
accessNode: 'http://127.0.0.1:8888',
_55
discoveryWallet: 'http://localhost:8701/fcl/authn',
_55
discoveryAuthInclude: []
_55
},
_55
testnet: {
_55
accessNode: 'https://rest-testnet.onflow.org',
_55
discoveryWallet: 'https://fcl-discovery.onflow.org/testnet/authn',
_55
discoveryAuthnEndpoint: 'https://fcl-discovery.onflow.org/api/testnet/authn',
_55
// Adds in Dapper + Ledger
_55
discoveryAuthInclude: ["0x82ec283f88a62e65", "0x9d2e44203cb13051"]
_55
},
_55
mainnet: {
_55
accessNode: 'https://rest-mainnet.onflow.org',
_55
discoveryWallet: 'https://fcl-discovery.onflow.org/authn',
_55
discoveryAuthnEndpoint: 'https://fcl-discovery.onflow.org/api/authn',
_55
// Adds in Dapper + Ledger
_55
discoveryAuthInclude: ["0xead892083b3e2c6c", "0xe5cd26afebe62781"]
_55
}
_55
};
_55
_55
const network = 'emulator';
_55
_55
config({
_55
"app.detail.title": "Emerald Academy", // the name of your DApp
_55
"app.detail.icon": "https://academy.ecdao.org/favicon.png", // your DApps icon
_55
"flow.network": network,
_55
"accessNode.api": fclConfigInfo[network].accessNode,
_55
"discovery.wallet": fclConfigInfo[network].discoveryWallet,
_55
"discovery.authn.endpoint": fclConfigInfo[network].discoveryAuthnEndpoint,
_55
// adds in opt-in wallets like Dapper and Ledger
_55
"discovery.authn.include": fclConfigInfo[network].discoveryAuthInclude
_55
});
_55
_55
export default function App() {
_55
const [user, setUser] = useState({ loggedIn: false, addr: "" });
_55
_55
// So that the user stays logged in
_55
// even if the page refreshes
_55
useEffect(() => {
_55
currentUser.subscribe(setUser);
_55
}, []);
_55
_55
return (
_55
<div className="App">
_55
<button onClick={authenticate}>Log In</button>
_55
<button onClick={unauthenticate}>Log Out</button>
_55
<p>{user.loggedIn ? `Welcome, ${user.addr}!` : "Please log in."}</p>
_55
</div>
_55
);
_55
}

Account/Address creation​

You can create a new account by using the AuthAccount constructor. When you do this, make sure to specify which account will pay for the creation fees by setting it as the payer.

The account you choose to pay these fees must have enough money to cover the cost. If it doesn't, the process will stop and the account won't be created.


_14
transaction(publicKey: String) {
_14
prepare(signer: AuthAccount) {
_14
let key = PublicKey(
_14
publicKey: publicKey.decodeHex(),
_14
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
_14
)
_14
let account = AuthAccount(payer: signer)
_14
account.keys.add(
_14
publicKey: key,
_14
hashAlgorithm: HashAlgorithm.SHA3_256,
_14
weight: 1000.0
_14
)
_14
}
_14
}

To create a new Flow account refer to these resources

Get Flow Balance​

Retrieving the token balance of a specific account involves writing a script to pull data from onchain. The user may have both locked tokens as well as unlocked so to retrieve the total balance we would aggregate them together.


_31
import * as fcl from "@onflow/fcl"
_31
import * as t from "@onflow/types"
_31
const CODE = `
_31
import "FungibleToken"
_31
import "FlowToken"
_31
import "LockedTokens"
_31
_31
pub fun main(address: Address): UFix64 {
_31
let account = getAccount(address)
_31
let unlockedVault = account
_31
.getCapability(/public/flowTokenBalance)!
_31
.borrow<&FlowToken.Vault{FungibleToken.Balance}>()
_31
?? panic("Could not borrow Balance reference to the Vault")
_31
let unlockedBalance = unlockedVault.balance
_31
let lockedAccountInfoCap = account
_31
.getCapability
_31
<&LockedTokens.TokenHolder{LockedTokens.LockedAccountInfo}>
_31
(LockedTokens.LockedAccountInfoPublicPath)
_31
if lockedAccountInfoCap == nil || !(lockedAccountInfoCap!.check()) {
_31
return unlockedBalance
_31
}
_31
let lockedAccountInfoRef = lockedAccountInfoCap!.borrow()!
_31
let lockedBalance = lockedAccountInfoRef.getLockedAccountBalance()
_31
return lockedBalance + unlockedBalance
_31
}`
_31
export const getTotalFlowBalance = async (address) => {
_31
return await fcl.decode(await fcl.send([
_31
fcl.script(CODE),
_31
fcl.args([fcl.arg(address, t.Address)])
_31
]))
_31
}

Contributing​

Releasing a new version of Dev Wallet is as simple as tagging and creating a release, a Github Action will then build a bundle of the Dev Wallet that can be used in other tools (such as CLI). If the update of the Dev Wallet is required in the CLI, a seperate update PR on the CLI should be created. For more information, please visit the fcl-dev-wallet GitHub repository.

More​

Additionally, consider exploring these resources: