This is a fork of flow-hydraulics/flow-wallet-api which was forked so that we could manage deployment and customize configuration specifically for Electables.
-
It is recommended to run the
flow-wallet-api
locally via Docker Compose, so make sure you've installed Docker and Docker Compose. You can install both by downloading Docker Desktop. -
Create a
.env
config file and copy the contents of.env.numero.example
into it:cp .env.numero.example .env
-
Start the Wallet API, Flow Emulator, Postgres DB and Redis from docker-compose, and make sure to pass our specify to use our custom
docker-compose.numero.yml
file:docker-compose -f docker-compose.numero.yml up
- The first time you run this command, it will take a while because it needs to pull the necessary docker images.
- If you want to run this in detached mode, pass
-d
to the command above. - If you want to rebuild the docker images, pass
--build
to the command above.
-
The API can be accessed at http://localhost:3005/v1
-
To stop the containers, run:
docker-compose down
To accommodate customizations for our setup, we have a several custom files: docker-compose.numero.yml
, numero.Dockerfile
and .env.numero.example
. Hopefully having custom files will allow us to upgrade the repository, by merging updates from https://github.com/flow-hydraulics/flow-wallet-api, without merge conflicts.
-
docker-compose.numero.yml
- Includes exposing the Flow Emulator port 3569 to the host machine so that we can deploy our contracts for local development.
- Adds
DATABASE_URL
andPORT
env vars to the api so that we can more closely mimic how we're starting up the service Heroku -DATABASE_URL
andPORT
are both set by Heroku in deployment.
-
numero.Dockerfile
- Located at the root of the project instead of the
docker
directory. We need the Docker image to be aware of the root of the project for its context, so we can copy thego.mod
,go.sum
andcustom_account_setup.cdc
files. In Heroku you're not able to set the context to a custom location - it has to be in the same directory as the Dockerfile. - Builds the
dist
build step fromalpine:3.15
instead ofscratch
so we have access to/bin/sh
for theCMD
step. - Uses
CMD
instead ofENTRYPOINT
so that Heroku is able to figure out how to start the service up properly. - Passes in several environment variables from the Heroku setup that are needed to start the service. For local development we're setting those in the
docker-compose.numero.yml
file.
- Located at the root of the project instead of the
-
.env.numero.example
- Sets the
FLOW_WALLET_JOB_STATUS_WEBHOOK
environment variable to http://host.docker.internal:8080/flow_wallet_api/webhook so that the API will post back toelectables-smart-contracts
, when it is also running on the host machine. - Sets
FLOW_WALLET_SCRIPT_PATH_CREATE_ACCOUNT
so that we are able to use custom_account_setup.cdc script to create an Electables collection for every new account created. - Sets
FLOW_WALLET_ADMIN_PRIVATE_KEY
to the private key used in local development forelectable-smart-contracts
.
- Sets the
See the upstream README below for additional information.
The Flow Wallet API is a REST HTTP service that allows a developer to integrate wallet functionality into a larger Flow application infrastructure. This service can be used by an application that needs to manage Flow user accounts and the assets inside them.
- Create new Flow accounts
- Securely store account private keys
- Send a transaction from an account
- Transfer fungible tokens (e.g. FLOW, FUSD)
- Detect fungible token deposits
- Transfer NFTs (e.g. FLOW, FUSD) (coming soon)
- Detect NFT deposits (coming soon)
View full list of functionality in the API documentation.
Some application developers may wish to manage Flow accounts in a fully-custodial fashion, but without taking on the complexity of building an account management system.
An application may need to support custody of fungible tokens (FLOW, FUSD), non-fungible tokens, or both.
For security and/or legal reasons, some developers need to use a custody service running on-premises as part of their existing infrastructure, rather than a hosted 3rd-party solution.
- FLOW/FUSD Hot Wallet — an application that allows users to convert fiat currency to FLOW or FUSD. A single admin account would be used as a hot wallet for outgoing payments, and additional deposit accounts would be created to accept incoming payments.
- Exchange — a cryptocurrency exchange that is listing FLOW and/or FUSD. Similar to the case above, one or more admin accounts may be used as a hot wallet for outgoing payments, and additional deposit accounts would be created to accept incoming payments.
- Web Wallet — a user-facing wallet application that is compatible with Flow dapps. Each user account would be created and managed by the wallet service.
View the Wallet API documentation and OpenAPI (Swagger) specification.
The Wallet API is provided as a Docker image:
docker pull ghcr.io/flow-hydraulics/flow-wallet-api:latest
NOTE: This setup is only for demonstrative purposes, please do not run this on production
This setup requires Docker, Docker Compose and the Flow CLI.
Create a configuration file:
cp .env.example .env # and edit
Start the Wallet API, Flow Emulator, Postgres and Redis:
docker-compose up -d
You can now access the API at http://localhost:3000/v1.
Once you're finished, run this to stop the containers:
docker-compose down
The application is configured using environment variables. Make sure to prefix variables with "FLOW_WALLET_"
If you have an existing .env
file (or you were using -envfile
) you can run a command with the variables loaded:
# Replace <command> with the command you want to run
env $(grep -e '^#' .env | xargs) <command>
# For example
env $(grep -e '^#' .env | xargs) go run main.go
You can put the service in maintenance mode via the System API by sending the following JSON body as a POST
request to /system/settings
(example in api-test-scripts/system.http):
{
"maintenanceMode": true
}
In maintenance mode, all on-chain transactions and event processing are halted. Disabling maintenance mode is done via the same API endpoint ("maintenanceMode": false
).
If you have the possibility to setup a webhook endpoint, you can set FLOW_WALLET_JOB_STATUS_WEBHOOK
to receive updates on async requests (requests which return a job). The wallet will send a POST
request to this URL containing the job whenever the status of the job is updated.
NOTE: The wallet expects a response with status code 200 and will retry if unsuccessful.
When making sync
requests it's sometimes required to adjust the server's request timeout. Try increasing FLOW_WALLET_SERVER_REQUEST_TIMEOUT
if you're experiencing issues with sync
requests, FLOW_WALLET_SERVER_REQUEST_TIMEOUT=180s
for example.
NOTE: Using sync
requests in production is not recommended, use asynchronous requests & optionally configure a webhook to receive job updates instead.
A comma separated list of fungible tokens and their corresponding addresses enabled for this instance. Make sure to name each token exactly as it is in the corresponding cadence code (FlowToken, FUSD etc.). Include at least FlowToken as functionality without it is undetermined.
NOTE: It is necessary to add a 3rd parameter "lowercamelcase" name for each token. For FlowToken this would be "flowToken" and for FUSD "fusd". This is used to construct the vault name, receiver name and balance name in generic transaction templates. Consult the contract code for each token to derive the proper name (search for .*Vault
, .*Receiver
, .*Balance
)
NOTE: Non-fungible tokens can not be enabled using environment variables. Use the API endpoints for that.
Examples:
FLOW_WALLET_ENABLED_TOKENS=FlowToken:0x0ae53cb6e3f42a79:flowToken,FUSD:0xf8d6e0586b0a20c7:fusd
Config variable | Environment variable | Description | Default | Examples |
---|---|---|---|---|
DatabaseType |
FLOW_WALLET_DATABASE_TYPE |
Type of database driver | sqlite |
sqlite , psql , mysql |
DatabaseDSN |
FLOW_WALLET_DATABASE_DSN |
Data source name (DSN) for database connection | wallet.db |
See below |
Examples of Database DSN
mysql://john:pass@localhost:3306/my_db
postgresql://postgres:postgres@localhost:5432/postgres
user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai
For more: https://gorm.io/docs/connecting_to_the_database.html
To learn more about database schema versioning and migrations, read MIGRATIONS.md.
Note: In order to use Google KMS for remote key management you'll need a Google Cloud Platform account.
Pre-requisites:
- Create a new Project if you don't have one already. You'll need the Project ID later.
- Enable Cloud Key Management Service (KMS) API for the project, Security -> Cryptographic Keys.
- Create a new Key Ring for your wallet (or use an existing Key Ring), Security -> Cryptographic Keys -> Create Key Ring, you'll need the Location ID (or Location) and Key Ring ID (or Name) later.
Using a Service Account to access the KMS API (see official docs for more);
- Create a new Service Account, IAM & Admin -> Service Accounts -> Create Service Account
- Use the roles
Cloud KMS Admin
&Cloud KMS Signer/Verifier
or grant the required permissions through a custom role (NOTE: deletion not supported yet):cloudkms.cryptoKeyVersions.useToSign
cloudkms.cryptoKeyVersions.viewPublicKey
cloudkms.cryptoKeys.create
- After creating the Service Account, select Manage Keys from the Actions menu in the Service Account listing.
- Create a new key, Add Key -> Create New key, and select JSON as the key type.
- Save the JSON file.
Configure the Google KMS client library by setting the environment variable GOOGLE_APPLICATION_CREDENTIALS
:
export GOOGLE_APPLICATION_CREDENTIALS="/home/example/path/to/service-account-file.json"
Configure Google KMS as the key storage for flow-wallet-api
and set the necessary environment variables:
Config variable | Environment variable | Description | Default | Examples |
---|---|---|---|---|
DefaultKeyType |
FLOW_WALLET_DEFAULT_KEY_TYPE |
Default key type | local |
local , google_kms |
ProjectID |
FLOW_WALLET_GOOGLE_KMS_PROJECT_ID |
GCP Project ID | - | flow-wallet-example |
LocationID |
FLOW_WALLET_GOOGLE_KMS_LOCATION_ID |
GCP Location ID | - | europe-north1 , us-west1 |
KeyRingID |
FLOW_WALLET_GOOGLE_KMS_KEYRING_ID |
GCP Key Ring ID | - | example-wallet-keyring |
If you want to use a key stored in Google KMS for the admin account, just pass the resource identifier as the private key (FLOW_WALLET_ADMIN_PRIVATE_KEY
) and set FLOW_WALLET_ADMIN_KEY_TYPE
to google_kms
.
Creating an account on testnet via the faucet:
- When generating the key, choose "Asymmetric sign" as the purpose and "Elliptic Curve P-256 - SHA256 Digest" as the key type and algorithm (other combinations may work but these have been confirmed to work)
- Download the public key from Google KMS in PEM format (should have a
.pub
ending) - Run it through
flow keys decode pem --from-file <filename>
- Copy the "Public Key" part
- Go to https://testnet-faucet-v2.onflow.org
- Paste the copied public key in the form
- IMPORTANT: Choose SHA2_256 as the hash algorithm (SHA3_256 won't work with the key setup above)
- Copy the new address and use it as the
FLOW_WALLET_ADMIN_ADDRESS
- Set
FLOW_WALLET_ADMIN_PRIVATE_KEY
to the resource id of the key - Set
FLOW_WALLET_ADMIN_KEY_TYPE
togoogle_kms
Example environment:
FLOW_WALLET_ADMIN_ADDRESS=0x1234567890123456
FLOW_WALLET_ADMIN_PRIVATE_KEY=projects/<project_id>/locations/<location_id>/keyRings/<keyring_id>/cryptoKeys/<key_name>/cryptoKeyVersions/<version_number> # Make sure this ends with the version number
FLOW_WALLET_ADMIN_KEY_TYPE=google_kms
NOTE: This will mess up the docker-compose setup (emulator won't start) as it uses FLOW_WALLET_ADMIN_PRIVATE_KEY
as FLOW_SERVICEPRIVATEKEY
. It will cause an encoding error on the emulator.
Before configuring a Google KMS key for database encryption please refer to the official guide for setting up a symmetric encryption key;
https://cloud.google.com/kms/docs/encrypt-decrypt#before_you_begin
If you want to use an Google KMS symmetric encryption key for encrypting the stored account keys, please refer to the following configuration settings;
Config variable | Environment variable | Description | Default | Examples value for Google KMS |
---|---|---|---|---|
EncryptionKeyType |
FLOW_WALLET_ENCRYPTION_KEY_TYPE |
Encryption key type | local |
google_kms |
EncryptionKey |
FLOW_WALLET_ENCRYPTION_KEY |
KMS encryption key resource name | - | projects/my-project/locations/us-west1/keyRings/my-keyring/cryptoKeys/my-encryption-key |
Note: In order to use AWS KMS for remote key management you'll need an AWS account. Note: Custom key stores are not supported.
- AWS credentials for an account that has access to KMS
Environment variable | Description | Default | Examples |
---|---|---|---|
AWS_PROFILE |
AWS profile name, when using a shared credentials file | - | my-aws-profile-name |
AWS_REGION |
AWS KMS Region | - | eu-central-1 , us-west-1 |
AWS_ACCESS_KEY_ID |
AWS access key ID | - | AKIAXXX123FOOBAR1234 |
AWS_SECRET_ACCESS_KEY |
AWS secret access key | - | FooBaRBaZ12345... |
Configure AWS KMS as the key storage for flow-wallet-api
and set the necessary environment variables, with the default key type as aws_kms
:
Config variable | Environment variable | Description | Default | Value for AWS KMS |
---|---|---|---|---|
DefaultKeyType | FLOW_WALLET_DEFAULT_KEY_TYPE |
Default key type | local |
aws_kms |
If you want to use a key stored in AWS KMS for the admin account, please refer to the following configuration settings;
Config variable | Environment variable | Description | Default | Example value for AWS KMS |
---|---|---|---|---|
AdminKeyType |
FLOW_WALLET_ADMIN_KEY_TYPE |
Admin key type | local |
aws_kms |
AdminPrivateKey |
FLOW_WALLET_ADMIN_PRIVATE_KEY |
Admin private key ARN | - | arn:aws:kms:eu-central-1:012345678910:key/00000000-aaaa-bbbb-cccc-12345678910 |
When testing make sure to add the key to the admin account. You can convert the AWS public key (e.g. aws.pem
) you downloaded/copied from AWS with flow-cli;
flow keys decode pem --from-file=aws.pem --sig-algo "ECDSA_secp256k1"
If you want to use an AWS KMS symmetric encryption key for encrypting the stored account keys, please refer to the following configuration settings;
Config variable | Environment variable | Description | Default | Examples value for AWS KMS |
---|---|---|---|---|
EncryptionKeyType |
FLOW_WALLET_ENCRYPTION_KEY_TYPE |
Encryption key type | local |
aws_kms |
EncryptionKey |
FLOW_WALLET_ENCRYPTION_KEY |
KMS encryption key ARN | - | arn:aws:kms:eu-central-1:012345678910:key/00000000-aaaa-bbbb-cccc-12345678910 |
Idempotency middleware ensures that POST
requests are idempotent. When the middleware is enabled an Idempotency-Key
HTTP header is required for POST
requests. The header value should be a unique identifier for the request (UUID or similar is recommended). Trying to send a request with a duplicate idempotency key will result in a 409 Conflict
HTTP response.
To configure the middleware set the following configuration settings;
Config variable | Environment variable | Description | Default | Examples |
---|---|---|---|---|
DisableIdempotencyMiddleware |
FLOW_WALLET_DISABLE_IDEMPOTENCY_MIDDLEWARE |
Disable the idempotency middleware entirely | false |
true , false |
IdempotencyMiddlewareDatabaseType |
FLOW_WALLET_IDEMPOTENCY_MIDDLEWARE_DATABASE_TYPE |
Database type for idempotency key middleware | local |
local , shared , redis |
IdempotencyMiddlewareRedisURL |
FLOW_WALLET_IDEMPOTENCY_MIDDLEWARE_REDIS_URL |
Redis URL for idempotency key middleware storage | - | redis://walletapi:wallet-api-redis@localhost:6379/ |
NOTE:
- The
local
option forIdempotencyMiddlewareDatabaseType
does not support multiple instances. - The provided
docker-compose.yml
provides a basic Redis instance for local development purposes, with basic configuration files in theredis-config
directory. - There is currently no automatic cleanup of old idempotency keys when using the
shared
(sql) database. Redis is recommended for production use.
The default log level of the service is info
. You can change the log level by setting the environment variable FLOW_WALLET_LOG_LEVEL
.
Valid log leves are (case-insensitive):
panic
fatal
error
warn, warning
info
debug
trace
To enable multiple keys for custodial accounts you'll need to set FLOW_WALLET_DEFAULT_ACCOUNT_KEY_COUNT
to the number of keys each account should have. When a new account is created the auto-generated account key is cloned so that the total number of keys matches the configured value.
NOTE: Changing FLOW_WALLET_DEFAULT_ACCOUNT_KEY_COUNT
does not affect existing accounts.
Refer to configs/configs.go for details and documentation.
The Flow Wallet API is developed and maintained by Equilibrium, with support from the Flow core contributors.
You can run a fully dockerized test suite if you have Docker and Docker Compose installed.
# Run the test suite
make run-test-suite
# If you don't want to leave background services running (database, redis, flow-emulator)
make stop-test-suite