What is GigaWallet?
Dogecoin GigaWallet is a backend service which provides a convenient integration API for platforms such as online shops, exchanges, social media platforms etc, to accept and transact Dogecoin on behalf of their users.
The purpose of the GigaWallet is to promote the rapid uptake of Dogecoin as a payment option, by taking the complexity and risk out of integrating Dogecoin payments into business.
It's dangerous to go alone, take this? Maybe!
⚠️ Note: GigaWallet is a software-engineering component for anyone looking to integrate Dogecoin into their product, this is not a user-facing Dogecoin wallet. If you are a user looking for a dogecoin wallet you can search the wallet index on the dogecoin.com website.
It is expected that you are a comfortable with managing server infrastructure and integrating with REST APIs. GigaWallet is a service that must be deployed behind a firewall that protects it's sensitive APIs from the public internet, to which you will integrate your public-facing systems.
Effort has been taken to create a system which integrates with your platform, and so the APIs for Accounts all require a foreignID which represents the account from your system.
GigaWallet manages it's own database to track HD wallets, Invoices, UTXOs and other data it needs, however it is not a general-purpose shopping cart or user management system, it is expected that you will provide what you need on your side to create the magic ✨ you have in mind, good luck adventurer!
Basic Concepts
GigaWallet has been designed as a drop-in solution for anyone who needs to accept Dogecoin and respond in a timely manner when payment arrives.
From individual stores who need a Dogecoin checkout solution to global social media networks with millions of users recieving and sending each-other tips or payments, GigaWallet aims to be adaptable to each scenario. To achieve this aim we have some simple abstractions for managing payment:
Accounts
An Account manages a Dogecoin HD wallet, which is used to sign transactions for outgoing payments, and create child-addresses for each Invoice issued.
Accounts are created using the POST /account
Admin API, and require a
foreignID from your system which will be used to address the account on
further API calls.
Accounts have many Invoices which represent requests for payment, as well as a Balance which tracks current available Dogecoin and current pending incoming and outgoing transactions.
How you map Accounts to your system depends on your objective, you may have an account per user in the case of a Social Media platform, or if you are an entity with a number of clients you could choose to manage each with their own pay-to account.
You can read more about Accounts here.
Invoices
Accounts are used to issue Invoices, which are a collection of Items with quantities and values. Items represent a line on the invoice and come in a number of types: item, tax, fee, shipping, discount, donation, etc.
An invoice is created using the POST /account/:foreignID/invoice
Admin API
and once created cannot be modified, GigaWallet is not a shopping-cart system
and if you want users to be able to add/remove items that should happen on
your side before an Invoice is issued.
Invoices provide payment URLs, QRCodes and DogeConnect JSON Payloads via the Public API which can be used by your front-end to provide convenience payment options for your users.
You can read more about Invoices here.
Dogecoin Connect
Public API
Admin API
Installation
Pre-requisites
GigaWallet is intentionally easy to compile and run, weather you are looking to build from source or via containers, we've got you covered.
Golang compiler
To build from source you will need the Golang compiler installed. Head on over to go.dev and grab a copy for your local environment.
Dogecoin Core Node
GigaWallet currently depends on a co-located instance of the Dogecoin Core Node project, we recommend building this without the wallet / QT features, and with the RPC APIs.
⚠️ Important: Gigawallet trusts the Core Node to provide accurate blockchain data; for this reason is critically important to use a Core Node that you fully trust. It's safest to host the Core Node yourself.
If you would like to build this yourself or download binaries you can grab these at Github.com/dogecoin/dogecoin,
alternatively if you're happy with containers or packages try the NixOS or Docker deployment methods.
⚠️ Note: Running a full core node requires a significant amount of disk to contain the entire Dogecoin blockchain (140Gb as at March 2024), as well as a moderate amound of bandwidth.
Building from source
Install some dependencies required to build Gigawallet:
- GCC compiler toolchain (for cgo i.e. Go-to-C linking; only GCC is supported!)
- zeroMQ version 4 – docs wiki
- SQLite 3 – docs
sudo apt-get update
sudo apt-get install libzmq3-dev sqlite3 libsqlite3-dev build-essential pkg-config
On Windows: you can use WSL to install these tools, and build Gigawallet from inside the WSL environment (you can access windows drives via /mnt/c
etc.) Alternatively there is MSYS2 which provides a GCC build environment without using WSL.
On Mac: you can use Homebrew: brew install zmq pkg-config
– note that sqlite3
is pre-installed on modern macs. You can brew install git
if necessary.
Building Gigawallet
Check out the project from Github and run make
> git clone git@github.com:dogecoinfoundation/gigawallet.git
...
> cd gigawallet
> make
This will create a gigawallet
binary in /build/
.
gigawallet
has several subcommands:
./gigawallet server
starts the server running../gigawallet printconf
will dump out the config structure and exit../gigawallet setsyncheight <height>
will rewind the entire db and begin re-indexing from core, you probably don't need this.. probably.
⚠️ Note: Developer Shortcut If you are developing in the repository you can simply run
make dev
which will stand-up the server using the devconf.toml file. VS Code debugger also works.
Configuration
Config file location
By default the gigawallet
command will look for a config.toml
file in one of:
.
/etc/gigawallet/
$HOME/.gigawallet/
The name of the config file can be changed by providing the GIGA_ENV environment variable. This allows you to operate several different config files and switch between them, for instance if you have:
/etc/gigawallet/production.toml
/etc/gigawallet/staging.toml
You could switch between them with GIGA_ENV=production gigawallet <subcommands>
.
Eaxample config
There is an exmaple config file which is kept current with the software in the repo https://raw.githubusercontent.com/dogecoinfoundation/gigawallet/main/devconf.toml which you can use as a starting point.
Configure API ports
Gigawallet exposes two REST APIs:
-
Admin API which provides sensitive, internal functionality which is called from your own backend services, and must be protected behind a firewall.
-
Public API which provides web-facing routes for your front-end calls, for fetching Invoice data, QR codes for payments, and the Doge Connect protocol endpoints. We recommend this sit behind your load-balancer/proxy and be routed to as required for your needs.
pubapirooturl
is used internally when generating Doge Connect payloads to
allow clients to submit payments back to Gigawallet for processing.
[WebAPI]
adminbind = "localhost"
adminport = "8081"
pubbind = "localhost"
pubport = "8082"
pubapirooturl = "https://example.com/gigawallet"
Configure the data store
Gigawallet currently operates using SQLite or PostgreSQL databases. We recommend using sqlite for development / local testing, and PostgreSQL for production. Also note that you can easily extend Gigawallet for different databases, see Extending.
Running with sqlite (default)
[Store]
DBFile = "gigawallet.db"
Running with PostgreSQL
[Store]
DBFile = "postgres://username:password@localhost/gigawallet?sslmode=disable"
Currently Gigawallet PostgreSQL requires full permissions to create tables / indexes which is an unfortunate side-effect of our sqlite-first development, this will be changed in the future, however for now here is a quick-start for setting up a new DB:
-- create a database, you can call it whatever you like.
CREATE DATABASE gigawallet;
-- create a user, pick a better password than this!
CREATE USER gigawallet WITH PASSWORD 'up-up-down-down-left-right-left-right-b-a-start';
-- set the database owner and grant permissions
ALTER DATABASE gigawallet OWNER TO gigawallet;
GRANT ALL ON DATABASE gigawallet TO gigawallet;
As mentioned above, Gigawallet will create all tables it needs on first run.
Configuring Core access
As mentioned above, Gigawallet is currently designed to co-locate with a Core instance for communicating with the Dogecoin L1 network.
You can create as many [dogecoind.nnnnn]
sections as you like to represent access
to various Core instances you may have, which gets used is determined by the gigawallet.network
value.
[gigawallet]
network = "mainnet" # which dogecoind to connect to
[dogecoind.testnet]
host = "127.0.0.1"
zmqport = 28332
rpcport = 44555
rpcpass = "gigawallet"
rpcuser = "gigawallet"
[dogecoind.mainnet]
host = "127.0.0.1"
zmqport = 28332
rpchost = "127.0.0.1"
rpcport = 22555
rpcpass = "gigawallet"
rpcuser = "gigawallet"
Configuring Loggers
Gigawallet can create as many loggers as you like, these log events that cross the [internal event-bus]. Events have a type which is one of:
- SYS - System messages & errors.
- ACC - Account events.
- INV - Invoice events.
- NET - Network (L1) events.
- ALL - Synthetic type which catches all of the above.
Loggers are specified as a list of types and a path:
[loggers.events]
path = "./events.log"
types = ["ALL"]
[loggers.system]
path = "./system.log"
types = ["SYS"]
Configuring HTTP Callbacks
Callbacks or 'webhooks' are URLs which you can configure to recieve HTTP POST requests containing JSON-encoded event bodies. This can be used by your system to respond to events such as invoice paid etc.
To configure callbacks, provide a path and a type of event you'd like (see Loggers for a list)
[callbacks.example1]
path = "https://example.com/MyInvoiceEvents"
types = ["INV"]
Configuring MQTT topics
If http callbacks are not your thing, you can send events to an MQTT compatible message service.
Firstly use the [mqtt]
block to configure the server you'd like to connect to, then set up one
or more [mqtt.queues.*]
blocks with a topicfilter and types of events to send.
[mqtt]
address = "test.mosquitto.org:1884"
username = "rw"
password = "readwrite"
clientid = "gigawallet"
[mqtt.queues.accounts]
topicfilter = "account"
Types = ["ACC"]
Running with NixOS
TODO
Running with Docker
TODO
Working with Accounts
Gigawallet is designed as a backend component that sits within your infrastructure, and
as such is not supposed to be your system's user-database. It is designed with a fairly
generic Account
model which can be used as you see fit to match your business needs.
Each Account
within Gigawallet represents a Dogecoin HD Wallet, which is used to derive
child-addresses per Invoice
. Accounts can list invoices, refund payments and have a
Balance
of their own.
Accounts are created with a Foreign ID
which is provided by you and links the account
to your system. Most Admin APIs use this Foreign ID to reference internal accounts so
that you can easily integrate Gigawallet with your own systems.
Different ways to use Accounts with your system
Scenario 1 - Wholesale Store
You are a wholesale business selling dog-collars, dog-leads and accessories to pet stores.
You have a customers database
with a Customer ID
number for each pet store. You create a
Gigawallet Account
per customer using your Customer ID
as the Foreign ID
.
You can:
- Issue invoices to your customers, including shipping fees and taxes.
- List invoices per customer.
- Manage refunds with a 'wallet' per customer to ensure funds are accessible.
- Check total balances received and pay those out to your central wallet when ready.
Scenario 2 - Online Dogecoin Payments SaaS
You are a payment provider like PayPal, Square, etc. And are looking for a method to
manage Dogecoin payments. You have a users database
with a snowflake ID per user. You
create a Gigawallet Account
per user using your snowflake ID as the Foreign ID
.
You can:
- Issue invoices on behalf of your users.
- Automatically pay-out to your user's cold wallet based on various thresholds.
- Provide a realtime balance of user's funds.
- Provide reports on payments in and out over time.
Scenario 3 - Traditional Crypto Exchange
You are a traditional Crypto Exchange managing trades on behalf of your users. Gigawallet is configured with an account per user, consistent with your existing user databases.
You can:
- Recieve payment in Dogecoin from your users into their Dogecoin wallet for trading.
- Pay Dogecoin to your users wallet once trading is complete.
- Provide balance and reports on payments to and from their wallets.
- Configure auto-payouts to your users cold-wallet so they don't leave their Dogecoin on exchanges.
Scenario 4 - Global Scale platform ie: X.com, Twitch TV, EBay, etc.
You are a large scale unicorn with hundreds of millions of users. Your infrastructure teams can deploy Gigawallet in multiple configurations on your kubernetes clusters with appropriate auto-scaling and user sharding (in development). Gigawallet integrates directly into your existing stack with simple REST calls.
You can:
- Give each user the ability to recieve tips, accept and make payments, pay for products and subscriptions.
- Query balances and issue payouts to users personal wallets.
- Integrate Gigawallet directly into your messaging system (via MQTT) to trigger events when payments are confirmed.
- Help Dogecoin gain real utility as a global currency for all humanity.
Account Administration APIs
POST /account/:foreignID
Create or update an Account
:foreignID
is a gobal, (or shard)-unique identifier from your system which you will use
to address this account
in subsequent requests.
REQUEST BODY:
Expected POST Body, an empty {}
is fine to touch an account into existence.
{
"payout_address" : "<P2PKH Dogecoin Address>", // optional for auto-payout
"payout_threshold" : "<decimal amount of dogecoin before auto-payout>" //optional
"payout_frequency" : "<duration in seconds for time-based auto-payouts>" //optional
}
RESPONSE BODY:
Example response from POST {} /account/123456789
{
"foreign_id": "12345789",
"id": "DRQu6WR6bpU9N4rm87PvpWZLQSqmGgphFD",
"payout_address": "",
"payout_frequency": "",
"payout_threshold": "0"
}
Your account is now created with an HD wallet managed by Gigawallet.
GET /account/:foreignID
Get an Account
RESPONSE BODY:
Example response from GET /account/123456789
{
"foreign_id": "12345789",
"id": "DRQu6WR6bpU9N4rm87PvpWZLQSqmGgphFD",
"payout_address": "",
"payout_frequency": "",
"payout_threshold": "0"
}
GET /account/:foreignID/balance
Get an Account's AccountBalance
{
"CurrentBalance": "1000", // Current balance available for spending
"IncomingBalance": "24.89774", // Incoming payments which have not met the confirmation threshold
"OutgoingBalance": "0" // Outgoing payments which have not met the confirmation threshold
}
POST /account/:foreignID/pay
Send a payment from this account to an Address
REQUEST BODY:
{ "amount": "420.69, "to": "DPeTgZm7LabnmFTJkAPfADkwiKreEMmzio" }
Account Events
Events are available either via http callbacks or MQTT messages.
TODO
ACC_CREATED "CREATED"
ACC_UPDATED "UPDATED"
ACC_PAYMENT "PAYMENT"
ACC_CHAIN_ACTIVITY "CHAIN_ACTIVITY"
ACC_BALANCE_CHANGE "BALANCE_CHANGE"
Working with Invoices
Once you have Accounts established it's time to start issuing Invoices. Invoices are simply a list of items, services, taxes, fees, discounts etc. which a seller is offering for payment in Dogecoin.
📚 Wikipedia: An invoice, bill or tab is a commercial document issued by a seller to a buyer relating to a sale transaction and indicating the products, quantities, and agreed-upon prices for products or services the seller had provided the buyer.
As mentioned previously Gigawallet is not your general-purpose user database, just so it is not
your general purpose shopping-cart either. For this reason Invoices
are specifically
designed to encourage you to have finalised all purchase decisions before issuing an Invoice as the
final step when your user wants to pay in Dogecoin. Once created an invoice cannot be directly updated
(this is a design decision!) Gigawallet is a payment system for Dogecoin.
Parts of an Invoice
An invoice is created via the POST /account/:foreignID/invoice
endpoint and consists of a list of
items along with metadata about the status of the payment. Here is an example invoice:
{
"id": "DNBVSoHLhX4gQiGLdZJhXMe7XZWuD7orVo",
"items": [
{
"type": "item",
"name": "A segment of Toblerone",
"sku": "TOB001",
"description": "You can share my Toblerone, for 1 Dogecoin!",
"value": "1",
"quantity": 1,
"image_link": ""
}
],
"created": "2023-08-17T15:40:13.935244+10:00",
"total": "1",
"pay_to_address": "DNBVSoHLhX4gQiGLdZJhXMe7XZWuD7orVo",
"part_payment_detected": false,
"total_payment_detected": false,
"total_payment_confirmed": false,
"payment_unconfirmed": false,
"estimate_seconds_to_confirm": 0
}
id
This is a unique ID, it also happens to be the public child address generated from the account
HD wallet for this invoice. You'll notice it's identical to pay_to_address
for that reason, you
can use this to reference the invoice in future API calls or as a unique identifier for the
invoice in your own system.
items
Items is an array of line items that get passed in when the invoice is created, Items have a
value
which is a decimal amount of Dogecoin, as a string, per item. This is multiplied by
quantity
and summed across all items to derrive the invoice total
.
Items also have a type
which must be one of:
- item
- tax
- fee
- shipping
- discount
These types are primarily used to distinguish line-items in UI, so that taxes, shipping and fees
can be grouped separately. We do validate that all item values
are a positve amount, except for
items of type discount
which must be a negative amount.
total
This is the total calculated amount owing for the invoice to be considered paid, and is calculated as the sum of all item values * quantity. This is a decimal value as a string.
pay_to_address
This is the dogecoin address for recieving invoice payment.
part_payment_detected
This is a boolean flag that will be set when GigaWallet first detects any kind of payment in a block. This may or may not be the total amount owing.
total_payment_detected
This is a boolean flag that will be set when GigaWallet first detects a payment in a block that would complete the total amount owing.
total_payment_confirmed
This is a boolean flag that will be set when GigaWallet detects that required_confirmations
have
been met on the network, this is the best means of determining payment has been made.
payment_unconfirmed
This boolean will only be set in the event that required_confirmations
has been met and confirmed,
however the blockchain has forked and eliminated your payment. This should only occur in the event that
you are using a very low required_confirmations
count.
⚠️ Note: What should you do in this event? Did I just lose my Dogecoin?
GigaWallet cannot hide you from the reality of the blockchain and the potential for soft-forks, in day to day running we see these tip-reorgs happening semi regularly and removing 1 or at most 2 blocks of confirmation. In the event that a tip-reorg happens and that decrements the required number of confirmations or even eliminates your payment, it is highly likely that the transaction will be included in a new block shortly. GigaWallet will then re-issue and re-set the appropriate events / flags on the new tip.
It is possible that the payer has intentionally issued a double-spend transaction hoping to fake payment, we recommend that you set a
required_confirmations
value commensurate with the amount of Dogecoin in your invoice and the appropriate level of risk. If you are selling someone a Coffee for 30 Dogecoin perhaps a 1 block confirmation is fine, if you are selling a million dollar house, there is no reason not to wait for 20-30 confirmations, the ink will still be wet on the page anyway.
estimate_seconds_to_confirm
Once an intial payment has been seen, this value will be an estimate of the remaining seconds
before confirmation based on the required_confirmations
set for this Invoice. This is useful
for anyone using a poll-method to query payment as you can roughly predict the wait-time. If
no payment has been seen or the invoice is already paid this value will be 0.
Admin API
POST /account/:foreignID/invoice
_Create an Invoice
:foreignID
is the unique identifier from your system which you used to create an account
.
REQUEST BODY:
Expected POST Body:
{
"items": [
{
"name": "Dogecoin Sticker",
"value": "100.00",
"quantity": 1,
"type": "item"
}
],
"required_confirmations": 3
}
RESPONSE BODY:
{
"id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"items": [
{
"type": "item",
"name": "Dogecoin Sticker",
"sku": "",
"description": "",
"value": "100",
"quantity": 1,
"image_link": ""
}
],
"created": "2023-08-30T16:49:51.705419+10:00",
"total": "100",
"pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"part_payment_detected": false,
"total_payment_detected": false,
"total_payment_confirmed": false,
"payment_unconfirmed": false,
"estimate_seconds_to_confirm": 0
}
GET /account/:foreignID/invoice/:invoiceID
Get an Invoice for a specific account
:foreignID
is the unique identifier from your system which you used to create an account
.
:invoiceID
is the unique identifier for an invoice, ie: DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH
.
RESPONSE BODY:
{
"id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"items": [
{
"type": "item",
"name": "Dogecoin Sticker",
"sku": "",
"description": "",
"value": "100",
"quantity": 1,
"image_link": ""
}
],
"created": "2023-08-30T16:49:51.705419+10:00",
"total": "100",
"pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"part_payment_detected": false,
"total_payment_detected": false,
"total_payment_confirmed": false,
"payment_unconfirmed": false,
"estimate_seconds_to_confirm": 0
}
GET /account/:foreignID/invoices?limit=100&cursor=0
Enumerate an Invoice for a specific account.
:foreignID
is the unique identifier from your system which you used to create an account
.
limit
is the maximum number of records to return.
cursor
starts at 0, and should be set to the cursor
value returned by a previous call.
Those familiar with popular cursor-based APIs such as AWS etc should understand this pattern, it allows for machine-to-machine fetching of all invoices and should not be confused with an offset/limit style API.
The response contains two elements, items
which is an array of invoices, and cursor
which should be passed to the next invocation. A cursor of 0
indicates there are
no further records.
RESPONSE BODY:
{
"items": [
{
"id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"items": [
{
"type": "item",
"name": "Dogecoin Sticker",
"sku": "",
"description": "",
"value": "100",
"quantity": 1,
"image_link": ""
}
],
"created": "2023-08-30T16:49:51.705419+10:00",
"total": "100",
"pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"part_payment_detected": false,
"total_payment_detected": false,
"total_payment_confirmed": false,
"payment_unconfirmed": false,
"estimate_seconds_to_confirm": 0
}
],
"cursor": 0
}
Public API
The public invoice APIs are available on a different port which is designed to be exposed to the internet via your proxy or as part of your own API gateway. These APIs can be called by web or mobile clients, with the aim of providing payment info to the payer. We imagine you will use these apis to show the payer a list of items they are purchasing, and to provide details / address / QRcodes etc to facilitate payment.
GET /invoice/:invoiceID
Get an Invoice
:invoiceID
is the unique identifier for an invoice, ie: DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH
.
RESPONSE BODY:
{
"id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"items": [
{
"type": "item",
"name": "Dogecoin Sticker",
"sku": "",
"description": "",
"value": "100",
"quantity": 1,
"image_link": ""
}
],
"created": "2023-08-30T16:49:51.705419+10:00",
"total": "100",
"pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
"part_payment_detected": false,
"total_payment_detected": false,
"total_payment_confirmed": false,
"payment_unconfirmed": false,
"estimate_seconds_to_confirm": 0
}
GET /invoice/:invoiceID/qr.png
This endpoint does not return JSON, it returns a PNG image of a QR code containing a dogecoin address in the format:
dogecoin:<address>?amount=<amount>&ctx=<dogeconnect url>
The address
is the pay_to_address
in the invoice.
The amount
is the total
dogecoin in the invoice.
The ctx
is a URL that points to a dogecoin connect
payload.
This can be directly placed on your payment page and if scanned will load the user's Dogecoin wallet to make a payment for the full amount of the invoice. This could be used in a web interface, or even emailed or mailed with an invoice allowing immediate payment by the recipient.
GET /invoice/:invoiceID/connect
This endpoint returns a dogecoin connect
payload which is defined as a new protocol
to facilitate payment from a self-custodial wallet without needing access to a relay.
The concept is that a Dogecoin wallet which understands the dogecoin connect
protocol
can present in it's own UI, an invoice complete with items being purchased and have
the user generate a transaction
which can be issued back to GigaWallet directly where
it will be validated and sent to the mempool.
This will allow GigaWallet to support zero-confirmation
payments, aka instant payments
which are required for fast-turn-around services such as vending machines, coffee shops,
etc.
{
"version": "0.1",
"service_name": "Example Dogecoin Store",
"service_icon_url": "https://example.com/icon.png",
"service_domain": "example.com",
"service_key_hash": "...",
"payload": "eyJ0eXBlIjoiaW52b2ljZSIsInJlcXVlc3...",
"hash": "..."
}
The JSON body contains a payload
which is signed by the issuing store key which
can be stored on the client once recognised for the first time. This protocol is
still under development and support is incomplete, watch this space!