Docs Liquidapps Io en v2.0
Docs Liquidapps Io en v2.0
1 Developers 1
1.1 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Zeus Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Dapp Client Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.5 Kylin Testnet Account . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.6 Zeus IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.7 vRAM Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.8 LiquidAccounts Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.9 LiquidHarmony Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.10 LiquidScheduler Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.11 LiquidStorage Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.12 Contract Logs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.13 DAPP Network Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.14 Unit Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.15 Packages and Staking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
1.16 Zeus Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
1.17 Zeus Create Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
1.18 Create service boilerplate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2 DSPs 65
2.1 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.3 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.4 Demux Backend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.5 Account . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.6 EOSIO Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.7 IPFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
2.8 PostgreSQL Database Backend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.9 DSP Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.10 Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.11 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.12 Claim Rewards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.13 Replay Contract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.14 Cleanup IPFS and Oracle Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
2.15 Consumer Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
i
2.16 Upgrade DSP Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
3 Liquidx 91
3.1 LiquidX Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.2 Use DAPP Network Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.3 Become a DSP on another chain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
3.4 Example Chains to Add . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.5 Add a Chain to LiquidX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4 Covax 103
4.1 CoVax Chain Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.2 Become a DAPP Service Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.3 Become a Block Producer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
5 Services 111
5.1 LiquidAuthenticator Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.2 LiquidBilling Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
5.3 LiquidScheduler Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
5.4 LiquidDNS Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.5 LiquidArchive Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
5.6 LiquidVRAM Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
5.7 LiquidKMS Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
5.8 LiquidLog Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
5.9 LiquidHarmony Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
5.10 LiquidLens Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
5.11 LiquidLink Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
5.12 LiquidStorage Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
5.13 LiquidAccounts Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
5.14 VCPU Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
7 FAQs 127
7.1 Frequently Asked Questions The DAPP Token . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.2 Frequently Asked Questions DAPP Service Providers (DSPs) . . . . . . . . . . . . . . . . . . . . . 129
7.3 Frequently Asked Questions vRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
ii
CHAPTER 1
Developers
• Getting Started
• Unit Testing
• Packages and Staking
• Zeus boxes
• Getting Started
1.1.4 vRAM
• With Zeus
1.1.5 LiquidAccounts
1.1.6 LiquidHarmony
1
LiquidApps
1.1.7 LiquidScheduler
1.2 Overview
1.2.1 Articles
1.2.2 Videos
• Multi-Chain dApp Scaling: Intro to LiquidApps & the DAPP Network (Blockchain Tools by Peter Keay)
• Setting up LiquidApps’ Zeus SDK, including NVM + NPM (Blockchain Dev Tools by Peter Keay)
• Intro to Scalable, Decentralized Storage with DAPP Network vRAM (Blockchain Tools by Peter Keay)
• Developer Explains - Decentralized Dapp Scaling w/ IPFS! How LiquidApps Dapp Service Providers Work
• EOS Weekly - The LiquidApps Game-Changer
• EOS Weekly - Unlimited DSP Possibilities
2 Chapter 1. Developers
LiquidApps
1.3.1 Overview
Zeus-cmd is an extensible command line tool. SDK extensions come packaged in “boxes” and are served through
IPFS. Zeus is currently in alpha. As a note, all Zeus commands must be run within the root directory of the package
that was unboxed.
• zeus-sdk
• overview of boxes
1.3.2 Features:
If you want to be up and running with Zeus quickly, you can use our cloud based Zeus-IDE, all you need is a Github
account! Try it here!
The dapp-client library makes it easier to interact with the DAPP Network’s core smart contracts and services, read
more here.
• 16GB RAM
• 2 CPU Cores
1.3.6 Prerequisites
1.3.9 Update
1.3.10 Test
This box supports all DAPP Services and unit tests and is built to integrate your own DAPP Network logic. When you
run the command a sample unit test and smart contract will be created.
4 Chapter 1. Developers
LiquidApps
http://elemental.liquidapps.io/ | code
The game incorporates:
• vRAM - light-weight caching solution for EOSIO based RAM
• LiquidAccounts - EOSIO accounts that live in vRAM instead of RAM
• LiquidDNS - DNS service on the blockchain | contract table
• Frontend stored on IPFS
• user data is stored in the vRAM dapp::multi_index table (vRAM) | code
• keys stored in dapp::multi_index table | code
• keys created using the account name and password as seed phrases | code
• eosjs-ecc’s seedPrivate method is used to create the keypair | code
• logic to create LiquidAccount transactions | code
To launch locally:
https://chess.liquidapps.io/ | code
The game incorporates:
• vRAM - light-weight caching solution for EOSIO based RAM
• LiquidAccounts - EOSIO accounts that live in vRAM instead of RAM
• LiquidDNS - DNS service on the blockchain
• vCPU - a solution to scale blockchain processing power horizontally
To launch locally:
http://portfolio.liquidapps.io/ | code
LiquidPortfolio is a portfolio tracking tool for BTC, ETH (and tokens), and EOS (and tokens). The tool displays the
total current value of the portfolio while also encrypting all user account info with the LiquidAccount’s private key.
The game incorporates:
• vRAM - light-weight caching solution for EOSIO based RAM
note if you compile and run this contract yourself, you will need to update all instances of uint8[][] within the abi
to bytes[]
vRAM Boxes
The DAPP Service boxes allow you to isolate the service that you wish to work with. If you instead would like to use
all of the DAPP Services, you may unbox the all-dapp-services box.
• ipfs-dapp-service - utilize the dapp::multi_index table to store data in IPFS (vRAM) instead of RAM
• cron-dapp-service - schedule CRON tasks on-chain
• oracle-dapp-service - provide oracle services
• readfn-dapp-service - read a contract function without the need to submit a trx to the chain
• vaccounts-dapp-service - EOSIO accounts that live in vRAM instead of RAM
6 Chapter 1. Developers
LiquidApps
Miscellaneous Boxes
please note: zeus commands are directory sensitive, all commands should be performed in root of box
Zeus compile
Compile a smart contract. You can either compile all of the contracts within the contracts directory with zeus
compile or a specific contract by name, such as zeus compile dappservices
# optional flags:
Zeus migrate
Compile and migrate a smart contract to another network such as the Kylin Testnet, Jungle Testnet, or Mainnet.
Be sure to run the following commands from inside the directory you unboxed, e.g., if you unboxed coldtoken, be in
/coldtoken. Also be sure to set the network in the import and migrate commands so Zeus knows what chain the
keys / contract is operating on (mainnet, kylin, or jungle).
# optional flags:
Zeus test
Unit test a smart contract. To run the unit tests for all smart contracts within the unboxed directory, use zeus test.
The compile all smart contracts before testing, use zeus test -c, -c being the alias to compile. To test and or
compile for a specific contract name, add the <CONTRACT_NAME> to the command.
# optional flags:
8 Chapter 1. Developers
LiquidApps
Import and export keys to your Zeus wallet. Please note by default keys are imported without encryption.
# optional flags:
# optional flags:
Zeus uses 2 mapping files to unbox boxes. The builtin-mapping.json file is for boxes that are a part
of the official zeus-sdk repo (located: .../node_modules/@liquidapps/zeus-cmd/lib/resources/
builtin-mapping.json). This file only changes when Zeus is updated. There is also a local zeus box for
modifying existing boxes from the builtin-mapping.json and adding new boxes. If a box exists in both the
builtin and the local mapping files, the local mapping file will be used. To use the builtin box instead, you must remove
the local version first.
Zeus Deploy
Deploy a custom Zeus box to your local working directory. Once deployed, if the --update-mapping flag is used,
you may unbox this box like other packages. The --type method can be used to determine what medium to deploy
the box to. The default local deploys with the syntax file://${packagePath}/box.zip. The option ipfs
deploys to the IPFS network with the syntax ipfs://${hash}.
# optional flags:
--update-mapping # updates local mapping.json file with an IPFS URI where the package
˓→may be accessed at
# default: true
--type # deploy destination (local, ipfs)
# default: local
Zeus RC File
An RC file allows command flags specified in a json file to be used automatically without needing to add them to a
command each time it is used. To use an RC file, on can be created in the directory: ~/.zeus/zeusrc.json to
persist between deleting boxes and updating Zeus, or in another directory using the --rc-file flag to specify the
relative path.
Example RC file:
{
"verbose": true,
"type": "local",
"update-mapping": true,
"test": true,
"compile": true
}
Example usage:
Help
zeus --help
List Boxes
zeus list-boxes
10 Chapter 1. Developers
LiquidApps
Update Boxes
Directory structure
extensions/
contracts/
frontends/
models/
test/
migrations/
utils/
services/
zeus-box.json
zeus-config.js
zeus-box.json
{
"ignore": [
"README.md"
],
"commands": {
"Compile contracts": "zeus compile",
"Migrate contracts": "zeus migrate",
"Test contracts": "zeus test"
},
"install":{
"npm": {
}
},
"hooks": {
"post-unpack": "echo hello",
"post-install": "git clone ..."
}
}
zeus-config.js
Configure zeus environments available to interact with. The zeus-config.js file is located in the root of an
unboxed directory.
module.exports = {
defaultArgs:{
(continues on next page)
The dapp-client library makes using DAPP Network services much easier. It also allows you to easily tap into the
dappservices (core DAPP Network Smart contract) and dappairhodl1 (Air-HODL smart contract) RAM
tables with precision utilizing secondary and tertiary indices without the hassle.
To setup the library, first install it:
npm i -g @liquidapps/dapp-client
/*
* network: specify your network of choice: mainnet, kylin, jungle
* httpEndpoint: you may also specify an endpoint to use instead of our defaults
(continues on next page)
12 Chapter 1. Developers
LiquidApps
};
Finally, setup the service you would like to interact along with your smart contract name:
(async () => {
const service = await (await createClient()).service('ipfs','cardgame1112');
const response = await service.get_vram_row( "cardgame1112", "cardgame1112",
˓→"users", "nattests" );
console.log(response);
// { username: 'nattests',
// win_count: 0,
// lost_count: 0,
// game_data:
// { life_player: 5,
// life_ai: 5,
// deck_player:
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ],
// deck_ai:
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ],
// hand_player: [ 0, 0, 0, 0 ],
// hand_ai: [ 0, 0, 0, 0 ],
// selected_card_player: 0,
// selected_card_ai: 0,
// life_lost_player: 0,
// life_lost_ai: 0,
// status: 0 } }
})().catch((e) => { console.log(e); });
Here is a full list of service options. There are DAPP Network service extensions and dappservices /
dappairhodl1 RAM row calls.
vRAM - IPFS
/*
getClient()
* service name: ipfs
* contract name
LiquidAccounts
/*
getClient()
* service name: vaccounts
* contract name
service.push_liquid_account_transaction
* account name of contract with LiquidAcount code deployed
* private key of LiquidAccount
* action name: regaccount to register new account
* payload
* vaccount - name of LiquidAccount
*/
/*
getClient()
* service name: vaccounts
* contract name
service.push_liquid_account_transaction
* account name of contract with LiquidAcount code deployed
* private key of LiquidAccount
* action name: hello
* payload
* any - payload must match struct outline in the smart contract
*/
14 Chapter 1. Developers
LiquidApps
1.4.2 dappservices
/*
dappNetwork.get_package_info
* account name
* service name - service names are listed under the services section of the docs
˓→as the Contract name
*/
console.log(response);
// {
// api: 'https://kylin-dsp-2.liquidapps.io',
// package_json_uri: 'https://kylin-dsp-2.liquidapps.io/liquidaccts2.dsp-package.
˓→json',
// package_id: 'liquidaccts2',
// service: 'accountless1',
// provider: 'heliosselene',
// quota: '10.0000 QUOTA',
// package_period: 60,
// min_stake_quantity: '10.0000 DAPP',
// min_unstake_period: 3600,
// enabled: 0
// }
/*
dappNetwork.get_table_accountext
*/
/*
dappNetwork.get_table_accountext_by_account_service
* account name
* service name - service names are listed under the services section of the docs
˓→as the Contract name
*/
/*
dappNetwork.get_table_accountext_by_account_service_provider
* account name
* service name - service names are listed under the services section of the docs
˓→as the Contract name (continues on next page)
16 Chapter 1. Developers
LiquidApps
*/
/*
dappNetwork.get_table_package
* [limit] - optional limit for how many packages to return
*/
// package_id: 'package1',
// service: 'ipfsservice1',
// provider: 'heliosselene',
// quota: '1.0000 QUOTA',
// package_period: 86400,
// min_stake_quantity: '10.0000 DAPP',
// min_unstake_period: 3600,
// enabled: 1
// }
}
/*
dappNetwork.get_table_package_by_package_service_provider
* package name
* service name - service names are listed under the services section of the docs
˓→as the Contract name
* DSP name
* [limit] - optional limit for how many packages to return
*/
// package_id: 'package1',
// service: 'ipfsservice1',
// provider: 'heliosselene',
// quota: '1.0000 QUOTA',
// package_period: 86400,
// min_stake_quantity: '10.0000 DAPP',
// min_unstake_period: 3600,
// enabled: 1
// }
}
/*
dappNetwork.get_table_refunds
* account name
*/
18 Chapter 1. Developers
LiquidApps
/*
dappNetwork.get_table_staking
* account name
*/
1.4.3 dappairhodl1
/*
airhodl.get_dapphdl_accounts
* account name
*/
The CryptoKylin testnet is one of the EOS Testnets. Feel free to join their Telegram, or checkout their Github repo.
1.5.1 Account
# Create a new available account name (replace 'yourtestaccount' with your account
˓→name):
export ACCOUNT=yourtestaccount
# Configure endpoint
export DSP_ENDPOINT=https://kylin-dsp-1.liquidapps.io
# Create wallet
cleos wallet create --file wallet_password.pwd
cleos -u $DSP_ENDPOINT system delegatebw $ACCOUNT $ACCOUNT "20.0000 EOS" "80.0000 EOS
˓→" -p $ACCOUNT@active
DAPP Faucet
The Zeus IDE allows new developers to get up and running in mere minutes! It is based on Gitpod, a cloud-based
tool for creating IDEs from git repos backed by Docker containers. All a you need to do is log in to Gitpod with your
GitHub account and establish a new workspace based on the LiquidApps Zeus IDE GitHub repo.
Behind the scenes, Gitpod executes the following:
• Automatically installs the Docker image, which already contains EOSIO, Zeus and many other tools
• Starts an EOSIO development node
• Generates a basic starting point for a project (using the Zeus SDK)
• Starts a LiquidApps development DSP
Click here to try it!
20 Chapter 1. Developers
LiquidApps
_____ __ __
| __ \ /\ | \/ |
__ _| |__) | / \ | \ / |
\ \ / / _ / / /\ \ | |\/| |
\ V /| | \ \ / ____ \| | | |
\_/ |_| \_\/_/ \_\_| |_|
vRAM is a caching solution that enables DAPP Service providers (specialized EOS nodes) to load data to and from
RAM <> vRAM on demand. Data is evicted from RAM and stored in vRAM after the transaction has been run. This
works similar to the way data is passed to and from regular computer RAM and a hard drive. As with EOS, RAM is
used in a computer sometimes because it is a faster storage mechanism, but it is scarce in supply as well. For more
information on the technical details of the transaction lifecycle, please read the vRAM Guide For Experts article and/or
the whitepaper.
vRAM requires a certain amount of data to be stored in RAM permanently in order for the vRAM system to be trustless.
This data is stored in a regular eosio::multi_index table with the same name as the dapp::multi_index
vRam table defined by the smart contract. Each row in the regular eosio::multi_index table represents
the merkle root of a partition of the sharded data with the root hash being vector<char> shard_uri and
the partition id being uint64_t shard. Note that this is equivalent to having a single merkle root with
the second layer of the tree being written to RAM for faster access. The default amount of shards (which is
proportional to the maximum amount of permanent RAM required) is 1024 meaning that, the total amount of
RAM that a dapp::multi_index table will need to permanently use is 1024 * (sizeof(vector<char>
shard_uri) + sizeof(uint64_t id)).
In order to access/modify vRam entries certain data may need to be loaded into RAM in order to prove (via the merkle
root) that an entry exists in the table. This temporary data (the “cache”) is stored in the ipfsentry table. The DAPP
Services Provider is responsible for removing this data after the transaction’s lifecycle. If the DSP does not perform
this action, the ipfsentry table will continue to grow until the account’s RAM supply has been exhausted or the
DSP resumes its services.
1.7.1 Prerequisites
• Zeus - Zeus installs eos and the eosio.cdt if not already installed
• Kylin Account
This box supports all DAPP Services and unit tests and is built to integrate your own vRAM logic.
mkdir mydapp; cd mydapp
zeus unbox dapp --no-create-dir
zeus create contract mycontract
To use advanced multi index features include #define USE_ADVANCED_IPFS at the top of the contract file while
following the steps below. If you have already deployed a contract that does not use advanced features, do not add this
line, as it is not backwards compatible.
Another feature of the advanced multi index is warmuprow and cleanuprow actions. The warmuprow action
allows for faster warmups for IPFS actions. The warmup process is where data is fetched and loaded into RAM to be
used. Previously each RAM entry touched would require 3 separate warmup actions, now this can be done within 1
action. The cleanuprow action removes all the data entries created by the warmuprow in the case that a rollback
is required.
Additionally, vram tables from other contracts can now be read with the addition of the warmupcode action. This is
done the same way as a regular multi_index table by specifying a code other than _self. For example, by replacing:
my_table_struct mytable(_self,_self.value);
with
my_table_struct mytable(othercntr,othercntr.value);
This does require that the table struct and table name of the remote contract to be known, just as in regular multi_index.
Remote tables can only be read, they cannot be modified. Remote table owners do not have to be staked to the same
DSP as your contract.
in contracts/eos/mycontract/mycontract.cpp
#pragma once
#include "../dappservices/ipfs.hpp"
#include "../dappservices/multi_index.hpp"
#define DAPPSERVICES_ACTIONS() \
XSIGNAL_DAPPSERVICE_ACTION \
IPFS_DAPPSERVICE_ACTIONS
using std::string;
CONTRACT_START()
public:
22 Chapter 1. Developers
LiquidApps
private:
struct [[eosio::table]] vramaccounts {
asset balance;
uint64_t primary_key()const { return balance.symbol.code().raw(); }
};
1.7.6 Compile
See the unit testing section for details on adding unit tests.
zeus compile
# compile and test with
zeus test -c
export DSP_ENDPOINT=https://kylin-dsp-1.liquidapps.io
export KYLIN_TEST_ACCOUNT=<ACCOUNT_NAME>
export KYLIN_TEST_PUBLIC_KEY=<ACTIVE_PUBLIC_KEY>
# Buy RAM:
cleos -u $DSP_ENDPOINT system buyram $KYLIN_TEST_ACCOUNT $KYLIN_TEST_ACCOUNT "200.
˓→0000 EOS" -p $KYLIN_TEST_ACCOUNT@active
˓→"accounts\":[{\"permission\":{\"actor\":\"$KYLIN_TEST_ACCOUNT\",\"permission\":\
# Stake your DAPP to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappservices stake "[\"$KYLIN_TEST_ACCOUNT\",\"
˓→$PROVIDER\",\"$SERVICE\",\"10.0000 DAPP\"]" -p $KYLIN_TEST_ACCOUNT@active
1.7.9 Test
Finally you can now test your vRAM implementation by sending an action through your DSP’s API endpoint
cleos -u $DSP_ENDPOINT push action $KYLIN_TEST_ACCOUNT youraction1 "[\"param1\",\
˓→"param2\"]" -p $KYLIN_TEST_ACCOUNT@active
>> {"version":"1.0","etype":"service_request","payer":"yourcontract","service":
˓→"ipfsservice1","action":"commit","provider":"","data":"DH......"}
# zeus:
zeus get-table-row "CONTRACT_ACCOUNT" "TABLE_NAME" "SCOPE" "TABLE_PRIMARY_KEY"
˓→"KEYTYPE" "KEYSIZE" --endpoint $DSP_ENDPOINT | python -m json.tool
# key size (optional) - size of key in bits: 64 (uint64_t), 128 (uint128_t), 256
˓→(uint256_t, eosio::checksum256)
(continues on next page)
24 Chapter 1. Developers
LiquidApps
# curl:
curl http://$DSP_ENDPOINT/v1/dsp/ipfsservice1/get_table_row -d '{"contract":"CONTRACT_
˓→ACCOUNT","scope":"SCOPE","table":"TABLE_NAME","key":"TABLE_PRIMARY_KEY"}' | python -
˓→m json.tool
# coldtoken:
zeus get-table-row $KYLIN_TEST_ACCOUNT "accounts" $KYLIN_TEST_ACCOUNT "TEST" --
˓→endpoint $DSP_ENDPOINT | python -m json.tool
˓→json.tool
Reads all vRAM tables of a smart contract and stores them with the naming syntax:
${contract_name}-${table_name}-table.json. The script is located in the utils/
ipfs-service/get-table.js of an unboxed zeus box.
Mandatory env variables:
# defaults to all vRam tables in the abi, can be used to target a specific table
export TABLE_NAME=
# defaults to localhost:8888, can be used to specify external nodeos instance
export NODEOS_ENDPOINT=
# defaults to localhost, can be used to specify external IPFS instance
export IPFS_HOST=
# defaults to 5001
export IPFS_PORT=
# defaults to http
export IPFS_PROTOCOL=
# defaults to 1024
export SHARD_LIMIT=
# defaults to false
# produces a ${contractName}-${tableName}-roots.json file which is the table's
˓→current entries
# also produces an ipfs-data.json which can be used to recreate the current state of
˓→the IPFS table
export VERBOSE=
npm i -g @liquidapps/zeus-cmd
zeus unbox ipfs-dapp-service
cd ipfs-dapp-service
zeus test -c
export CONTRACT_NAME=test1
node utils/ipfs-service/get-table
"shard": 156
},
...
]
ipfs-data.json - produces all data necessary to recreate current state of the table, can be used for populating a
DSP’s IPFS cluster
{
"015512204cbbd8ca5215b8d161aec181a74b694f4e24b001d5b081dc0030ed797a8973e0":
˓→ "01000000000000000000000000000000",
"01551220b422e3b9180b32ba0ec0d538c7af1cf7ccf764bfb89f4cd5bc282175391e02bb":
˓→"77cc0000000000007f00000000000000",
...
}
Prints ordered vRAM table keys in ascending order account/table/scope. This can be used to iterate over the entire
table client side. The script is located in the utils/ipfs-service/get-ordered-keys.js of an unboxed
zeus box.
Mandatory env variables:
26 Chapter 1. Developers
LiquidApps
export CONTRACT_NAME=
export SCOPE=
export TABLE_NAME=
node utils/ipfs-service/get-ordered-keys
npm i -g @liquidapps/zeus-cmd
zeus unbox ipfs-dapp-service
cd ipfs-dapp-service
zeus test -c
export CONTRACT_NAME=test1
export SCOPE=test1
export TABLE_NAME=test
node utils/ipfs-service/get-ordered-keys
Expected output:
To enable these features, you must include the advanced multi index with: #define USE_ADVANCED_IPFS at the
top of the contract file. If you have already deployed a contract that does not use advanced features, do not add this
line, as it is not backwards compatible.
With that, you now have the ability to save the list of shards currently being used to represent the table’s current state.
With the saved snapshot, a developer can upload it to another contract, or version the snapshot and save it to be loaded
to the contract later. This adds much needed flexibility to maintaining database state in a vRAM table.
Using zeus, a backup file can be created with the following command:
# optional flags:
# example
zeus backup-table lqdportfolio users --endpoint=http://kylin-dsp-2.liquidapps.io/
Example: vram-backup-lqdportfolio-users-0-1578405972.json
{
"contract": "lqdportfolio",
"table": "users",
"timestamp": "2020-01-07T14:06:12.339Z",
"revision": 0,
"manifest": {
"next_available_key": 0,
"shards": 1024,
"buckets_per_shard": 64,
"shardbuckets": [
{
"key": 2,
"value":
˓→"015512202a1de9ce245a8d14b23512badc076aee71aad3aba30900e9c938243ce25b467d"
},
{
"key": 44,
"value":
˓→"015512205b43f739a9786fbe2c384c504af15d06fe1b5a61b72710f51932c6b62592d800"
},
...
]
}
}
Load manifest
Once a manifest is saved, it can be loaded with the following smart contract action.
[[eosio::action]] void testman(dapp::manifest man) {
testindex_t testset(_self,_self.value);
// void load_manifest(manifest manifest, string description)
// description is description item in the backup table
testset.load_manifest(man,"Test");
}
28 Chapter 1. Developers
LiquidApps
By calling the clear command, a table’s version is incremented via the revision param and the
next_available_key is reset
TABLE vconfig {
checksum256 next_available_key = empty256;
uint32_t shards = 0;
uint32_t buckets_per_shard = 0;
uint32_t revision = 0;
};
void clear() {
vconfig_sgt vconfigsgt(_code,name(TableName).value);
auto config = vconfigsgt.get_or_default();
config.revision++;
config.next_available_key = empty256; //reset the next available key
vconfigsgt.set(config,_code);
}
[[eosio::action]] void testclear() {
testindex_t testset(_self,_self.value);
testset.clear();
}
_ _ _ _ _
˓→ _
| | (_) __ _ _ _ (_) __| | / \ ___ ___ ___ _ _ _ __
˓→ | |____
| | | | / _` | | | | | | | / _` | / _ \ / __| / __| / _ \ | | | | | '_
˓→\ | __| / __|
| |___ | | | (_| | | |_| | | | | (_| | / ___ \ | (__ | (__ | (_) | | |_| | | |
˓→| | | |_ \__ \
|_____| |_| \__, | \__,_| |_| \__,_| /_/ \_\ \___| \___| \___/ \__,_| |_|
˓→|_| \__| |___/
|_|
LiquidAccounts are EOS accounts that are stored in vRAM instead of RAM. This drastically reduces the cost of
creating accounts on EOS. Another great place to understand the service is in the unit tests.
1.8.1 Prerequisites
• Zeus - Zeus installs eos and the eosio.cdt if not already installed
• Kylin Account
This box contains the LiquidAccounts smart contract libraries, DSP node logic, unit tests, and everything else needed
to get started integrating / testing the DAPP Network LiquidAccounts in your smart contract.
#define DAPPSERVICE_ACTIONS_COMMANDS() \
IPFS_SVC_COMMANDS()VACCOUNTS_SVC_COMMANDS()
CONTRACT_START()
30 Chapter 1. Developers
LiquidApps
/* EACH ACTION MUST HAVE A STRUCT THAT DEFINES THE PAYLOAD SYNTAX TO BE PASSED */
VACCOUNTS_APPLY(((dummy_action_hello)(hello))((dummy_action_hello)(hello2)))
CONTRACT_END((init)(hello)(hello2)(regaccount)(xdcommit)(xvinit))
To enable the usage of LiquidAccounts between contracts, the subscriber contract (contract that wishes to use Liq-
uidAccounts of another host contract) must add the #define VACCOUNTS_SUBSCRIBER definition to the smart
contract. The subscriber contract must also be staked to a DSP offering the LiquidAccounts service, but this DSP does
not need to be the same DSP as the DSP providing services to the host contract. In place of setting the CHAIN_ID
with the xvinit action (detailed below), the account name of the host account providing the LiquidAccounts (not
the DSP account) must be used in its place.
1.8.5 Compile
See the unit testing section for details on adding unit tests.
zeus compile
# test without compiling
zeus test
# compile and test with
zeus test -c
export DSP_ENDPOINT=https://kylin-dsp-2.liquidapps.io
export KYLIN_TEST_ACCOUNT=<ACCOUNT_NAME>
export KYLIN_TEST_PUBLIC_KEY=<ACTIVE_PUBLIC_KEY>
# Buy RAM:
(continues on next page)
˓→"accounts\":[{\"permission\":{\"actor\":\"$KYLIN_TEST_ACCOUNT\",\"permission\":\
1.8.7 Select and stake DAPP for DSP package | DSP Portal Link
export PROVIDER=heliosselene
export PACKAGE_ID=accountless1
# Stake your DAPP to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappservices stake "[\"$KYLIN_TEST_ACCOUNT\",\"
˓→$PROVIDER\",\"$SERVICE\",\"10.0000 DAPP\"]" -p $KYLIN_TEST_ACCOUNT@active
1.8.8 Test
First you’ll need to initialize the LiquidAccounts implementation with the chain_id of the platform you’re operating
on. If you are using the #define VACCOUNTS_SUBSCRIBER definition to use LiquidAccounts from another host
account, that host account must be used in place of the chain_id.
# kylin
export CHAIN_ID=5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191
cleos -u $DSP_ENDPOINT push action $KYLIN_TEST_ACCOUNT xvinit "[\"$CHAIN_ID\"]" -p
˓→$KYLIN_TEST_ACCOUNT
# if using VACCOUNTS_SUBSCRIBER
cleos -u $DSP_ENDPOINT push action $KYLIN_TEST_ACCOUNT xvinit "[\"$HOST_ACCOUNT_NAME\
˓→"]" -p $KYLIN_TEST_ACCOUNT
Then you can begin registering accounts. You will need to do this either in a nodejs environment using the
dapp-client-lib, or you can use the zeus vaccounts push-action. Here is an example of using the lib
to register an account..
All payloads must include a key value pair with "vaccount":"vaccountname" or the transaction will fail. This
is so the dapp-client can fetch the nonce associated with the LiquidAccount.
32 Chapter 1. Developers
LiquidApps
dapp-client
Push LiquidAccount actions easily with zeus’s wrapper of the dapp-client library. You can pass a --dsp-url
for your DAPP Service Provider’s API endpoint. Then pass the name of the contract that the LiquidAccount code is
deployed to, the action name (regaccount for example), and the payload.
You also have the ability to store your private keys with or without encryption. If you choose to encrypt, you can pass
the --encrypted flag when creating a new account to store the keys. You can provide a password by command
line, or with the flag --password. If you use the account again, zeus will look for the key based on what network
you are operating on. If it finds it, it will use that key to sign and prompt for a password if needed.
# optional flags:
# development (local)
--storage-path # path to the wallet which will store the LiquidAccount key
# default: path.join(require('os').homedir(), '.zeus')
# Example:
zeus vaccounts push-action test1v regaccount '{"vaccount":"vaccount1"}'
zeus vaccounts push-action vacctstst123 regaccount '{"vaccount":"vaccount2"}' --
˓→private-key 5KJL... -u https://kylin-dsp-2.liquidapps.io
This file is under the utility/tool and it is for deserializing xvexec data (vaccount action data).
Example:
deserializeVactionPayload('dappaccoun.t', '6136465e000000002a00000000000000aca376f206b8fc25
'https://mainnet.eos.dfuse.io')
returns
{
"payload":{
"expiry":"1581659745",
"nonce":"42",
"chainid":"ACA376F206B8FC25A6ED44DBDC66547C36C6C33E3A119FFBEAEF943642F0E906",
"action":{
"account":"",
"action_name":"transfervacc",
"authorization":[
],
"action_data":
˓→"70AE375C19FEAA49E0D336557DF8AA49010000000000000004454F5300000000026869"
}
},
"deserializedAction":{
"payload":{
"vaccount":"dapjwaewayrb",
"to":"dapjkzepavdy",
"quantity":"0.0001 EOS",
"memo":"hi"
}
}
}
_ _ _ _ _ _
| | (_) (_) | | | | |
| | _ __ _ _ _ _ __| | |__| | __ _ _ __ _ __ ___ ___ _ __ _ _
| | | |/ _` | | | | |/ _` | __ |/ _` | '__| '_ ` _ \ / _ \| '_ \| | | |
| |____| | (_| | |_| | | (_| | | | | (_| | | | | | | | | (_) | | | | |_| |
|______|_|\__, |\__,_|_|\__,_|_| |_|\__,_|_| |_| |_| |_|\___/|_| |_|\__, |
| | __/ |
|_| |___/
LiquidHarmony includes all oracle related logic from the DAPP Network. This includes things like http fetches, IBC
and XIBC fetches, vCPU and more. The full list of options can be explored in the oracles directory of the repo:
https://github.com/liquidapps-io/zeus-sdk/tree/master/boxes/groups/oracles
The DAPP Network offers the ability to fetch information using DAPP Service Providers (DSPs). A developer may
choose as many or as few oracles to use in fetching data points from the internet. If a developer wishes to prevent a
scenario where all oracles have an incentive to return false information, the developer may run a DSP themselves and
set the threshold of acceptance for the information to all parties. Another great place to understand the service is in
the unit tests within each sub directory.
34 Chapter 1. Developers
LiquidApps
1.9.1 Prerequisites
• Zeus - Zeus installs eos and the eosio.cdt if not already installed
• Kylin Account
The DAPP Network currently supports the following oracle requests:
• HTTP(S) Get
• HTTP(S) Post
• HTTP(S)+JSON Get
• HTTP(S)+JSON Post
• Nodeos History Get
• IBC Block Fetch - (Mainnet, BOS, Telos, Kylin, Worbli, Jungle, Meetone)
• Oracle XIBC - read for foreign chain (Ethereum, Tron, Cardano, Ripple, Bitcoin, Litecoin, Bitcoin Cash)
• Wolfram Alpha
• Random Number
• Stockfish - chess engine AI
• SQL
This box contains the oracle smart contract libraries, DSP node logic, unit tests, and everything else needed to get
started integrating / testing the DAPP Network oracles in your smart contract.
Each of the following oracle request types comes equipped with its own syntax that gets encoded with Buffer.
from("<URI HERE>", 'utf8'). The following guide will explain the syntax to generate your URI. Each URI
should be passed through the buffer as plaintext is not accepted.
• HTTP(S) Get & Post: https://ipfs.io/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
- simply add the full URL path
• HTTP(S)+JSON Get: https+json://name/api.github.com/users/tmuskal - prepend your uri
with https+json, then specify the key mapping path of your desired data point, in the example, the name key
is used as the requested data point. To request nested values beneath the first layer of keys, simple separate the
desired data point with a ., e.g., name.value. Then add the path to your desired data point: api.github.
com/users/tmuskal. Note you may use http+json or https+json.
• HTTP(S)+JSON Post: https+post+json://timestamp/${body}/nodes.get-scatter.
com:443/v1/chain/get_block - where body is const body = Buffer.
from('{"block_num_or_id":"36568000"}').toString('base64'). In this example
you specify the type of request: https+post+json then the key mapping timestamp then the body of
the POST request, encoded in base64, then the URL path nodes.get-scatter.com:443/v1/chain/
get_block.
• Nodeos History Get: self_history://${code}/0/0/0/action_trace.act.data.account -
where code is const code = 'test1';
• IBC Block Fetch: sister_chain_block://bos/10000000/transaction_mroot - the
sister_chain_block specifies the type of oracle request, followed by the chain of choice bos
then the requested data point.
• Oracle XIBC: foreign_chain://ethereum/history/0x100/result.transactionsRoot -
here the foreign_chain oracle type is used followed by the foreign chain of choice: ethereum, the type
of data point (block_number, history, balance, storage). To see other blockchain data point op-
tions, see this file. Then the required data parameter is passed 0x100 followed by the object key mapping
result.transactionsRoot.
– You may also see more examples in the unit test
• Wolfram Alpha: wolfram_alpha://What is the average air speed velocity of a
laden swallow? - here the wolfram_alpha oracle type is used followed by the question: What is
the average air speed velocity of a laden swallow?.
#define DAPPSERVICE_ACTIONS_COMMANDS() \
ORACLE_SVC_COMMANDS()
CONTRACT_START()
/*
testget - provide a URI using the DAPP Network Oracle syntax and an expected
˓→ result,
if the result does not match the expected field, the transaction fails
testrnd - fetch oracle request based on URI without expected field assertion
*/
36 Chapter 1. Developers
LiquidApps
1.9.5 Compile
See the unit testing section for details on adding unit tests.
zeus compile
# test without compiling
zeus test
# compile and test with
zeus test -c
export DSP_ENDPOINT=https://kylin-dsp-2.liquidapps.io
export KYLIN_TEST_ACCOUNT=<ACCOUNT_NAME>
export KYLIN_TEST_PUBLIC_KEY=<ACTIVE_PUBLIC_KEY>
# Buy RAM:
cleos -u $DSP_ENDPOINT system buyram $KYLIN_TEST_ACCOUNT $KYLIN_TEST_ACCOUNT "200.
˓→0000 EOS" -p $KYLIN_TEST_ACCOUNT@active
˓→"accounts\":[{\"permission\":{\"actor\":\"$KYLIN_TEST_ACCOUNT\",\"permission\":\
1.9.7 Select and stake DAPP for DSP package | DSP Portal Link
export PROVIDER=heliosselene
export PACKAGE_ID=oracleservic
# Stake your DAPP to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappservices stake "[\"$KYLIN_TEST_ACCOUNT\",\"
˓→$PROVIDER\",\"$SERVICE\",\"10.0000 DAPP\"]" -p $KYLIN_TEST_ACCOUNT@active
1.9.8 Test
Finally you can now test your LiquidHarmony implementation by sending an action through your DSP’s API endpoint
export
˓→URI=68747470733a2f2f697066732e696f2f697066732f516d6169737a364e4d68444235316343764e576131474d53374c5
export EXPECTED_FIELD=48656c6c6f2066726f6d2049504653204761746577617920436865636b65720a
cleos -u $DSP_ENDPOINT push action $KYLIN_TEST_ACCOUNT testrnd "[\"$URI\"]" -p $KYLIN_
˓→TEST_ACCOUNT
_ _ _ _ ____ _ _
˓→ _
| | (_) __ _ _ _ (_) __| | / ___| ___ | |__ ___ __| | _ _
˓→ | | ___ _ __
| | | | / _` | | | | | | | / _` | \___ \ / __| | '_ \ / _ \ / _` | | | |
˓→| | | / _ \ | '__|
| |___ | | | (_| | | |_| | | | | (_| | ___) | | (__ | | | | | __/ | (_| | | |_|
˓→| | | | __/ | |
|_____| |_| \__, | \__,_| |_| \__,_| |____/ \___| |_| |_| \___| \__,_| \__,_
˓→| |_| \___| |_|
|_|
LiquidScheduler is an on chain cron solution for EOS based actions. One use case would be setting up LiquidHarmony
(oracle) fetches on a continual basis. Another great place to understand the service is in the unit tests.
1.10.1 Prerequisites
• Zeus - Zeus installs eos and the eosio.cdt if not already installed
• Kylin Account
38 Chapter 1. Developers
LiquidApps
This box contains the LiquidScheduler smart contract libraries, DSP node logic, unit tests, and everything else needed
to get started integrating / testing the DAPP Network LiquidScheduler in your smart contract.
#define DAPPSERVICE_ACTIONS_COMMANDS() \
CRON_SVC_COMMANDS()
CONTRACT_START()
/* SETUP COUNTER TABLE FOR HOW MANY TIME TO REPEAT CRON */
TABLE stat {
uint64_t counter = 0;
};
// reschedule
/* CAN return true TO CREATE INFINITE LOOP */
return (newstats.counter < 10);
}
/* */
[[eosio::action]] void testschedule() {
std::vector<char> payload;
(continues on next page)
1.10.4 Compile
See the unit testing section for details on adding unit tests.
zeus compile
# test without compiling
zeus test
# compile and test with
zeus test -c
export DSP_ENDPOINT=https://kylin-dsp-2.liquidapps.io
export KYLIN_TEST_ACCOUNT=<ACCOUNT_NAME>
export KYLIN_TEST_PUBLIC_KEY=<ACTIVE_PUBLIC_KEY>
# Buy RAM:
cleos -u $DSP_ENDPOINT system buyram $KYLIN_TEST_ACCOUNT $KYLIN_TEST_ACCOUNT "200.
˓→0000 EOS" -p $KYLIN_TEST_ACCOUNT@active
˓→"accounts\":[{\"permission\":{\"actor\":\"$KYLIN_TEST_ACCOUNT\",\"permission\":\
1.10.6 Select and stake DAPP for DSP package | DSP Portal Link
export PROVIDER=heliosselene
export PACKAGE_ID=cronservices
# Stake your DAPP to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappservices stake "[\"$KYLIN_TEST_ACCOUNT\",\"
˓→$PROVIDER\",\"$SERVICE\",\"10.0000 DAPP\"]" -p $KYLIN_TEST_ACCOUNT@active
40 Chapter 1. Developers
LiquidApps
1.10.7 Test
To test the sample contract, first check the stat table for the current counter value which should increase after the cron.
Then simply send a testschedule action to your smart contract’s account name.
Add your account_namez to the following curl to see if the counter increases.
testschedule
_ _ _ _ _____ _
| | (_) (_) | |/ ____| |
| | _ __ _ _ _ _ __| | (___ | |_ ___ _ __ __ _ __ _ ___
| | | |/ _` | | | | |/ _` |\___ \| __/ _ \| '__/ _` |/ _` |/ _ \
| |____| | (_| | |_| | | (_| |____) | || (_) | | | (_| | (_| | __/
|______|_|\__, |\__,_|_|\__,_|_____/ \__\___/|_| \__,_|\__, |\___|
| | __/ |
|_| |___/
LiquidStorage allows the read/write of data to a DAPP Service Provider’s IPFS node.
1.11.1 Prerequisites
• Zeus - Zeus installs eos and the eosio.cdt if not already installed
• Kylin Account
This box contains the LiquidStorage example smart contract, DAPP Service Provider node logic, unit tests, dapp-client
source code and examples.
# npm i -g @liquidapps/zeus-cmd
zeus unbox storage-dapp-service
cd storage-dapp-service
zeus test -c
./contracts/eos/storageconsumer/storageconsumer.cpp
The consumer contract is a great starting point for playing around with the LiquidStorage service. This sample contract
uses LiquidAccounts as an option, but the service may also be used with regular EOS accounts.
CONTRACT_START()
};
typedef eosio::singleton<"storagecfg"_n, storagecfg> storagecfg_t;
storagecfg.max_file_size_in_bytes = max_file_size_in_bytes;
storagecfg.global_upload_limit_per_day = global_upload_limit_per_day;
storagecfg.vaccount_upload_limit_per_day = vaccount_upload_limit_per_day;
storagecfg_table.set(storagecfg, get_self());
}
/* THE FOLLOWING STRUCT DEFINES THE PARAMS THAT MUST BE PASSED FOR A LIQUIDACCOUNT
˓→TRX */
42 Chapter 1. Developers
LiquidApps
EOSLIB_SERIALIZE(dummy_action_hello, (vaccount)(b)(c))
};
/* EACH ACTION MUST HAVE A STRUCT THAT DEFINES THE PAYLOAD SYNTAX TO BE PASSED */
VACCOUNTS_APPLY(((dummy_action_hello)(hello)))
CONTRACT_END((hello)(regaccount)(setstoragecfg)(xdcommit)(xvinit))
1.11.4 Compile
See the unit testing section for details on adding unit tests.
zeus compile
# test without compiling
zeus test
# compile and test with
zeus test -c
export DSP_ENDPOINT=https://kylin-dsp-2.liquidapps.io
export KYLIN_TEST_ACCOUNT=<ACCOUNT_NAME>
export KYLIN_TEST_PUBLIC_KEY=<ACTIVE_PUBLIC_KEY>
# Buy RAM:
cleos -u $DSP_ENDPOINT system buyram $KYLIN_TEST_ACCOUNT $KYLIN_TEST_ACCOUNT "200.
˓→0000 EOS" -p $KYLIN_TEST_ACCOUNT@active
˓→"accounts\":[{\"permission\":{\"actor\":\"$KYLIN_TEST_ACCOUNT\",\"permission\":\
1.11.6 Select and stake DAPP for DSP package | DSP Portal Link
# Stake your DAPP to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappservices stake "[\"$KYLIN_TEST_ACCOUNT\",\"
˓→$PROVIDER\",\"$SERVICE\",\"10.0000 DAPP\"]" -p $KYLIN_TEST_ACCOUNT@active
The setstoragecfg table allows setting limits to the LiquidStorage service for users. This is an optional step.
TABLE storagecfg {
// all measurements in bytes
uint64_t max_file_size_in_bytes = UINT64_MAX; // max file size in bytes that can be
˓→uploaded at a time, default 10mb
};
Here we will set the maximum file size to 1MB and the global upload limits to 10MB each. You can update the
YOUR_ACCOUNT_HERE to your consumer account.
cleos -u https://kylin.eos.dfuse.io push transaction '{"delay_sec":0,"max_cpu_usage_ms
˓→":0,"actions":[{"account":"YOUR_ACCOUNT_HERE","name":"setstoragecfg","data":{"max_
˓→file_size_in_bytes":1000000,"global_upload_limit_per_day":100000000,"vaccount_
˓→upload_limit_per_day":100000000},"authorization":[{"actor":"YOUR_ACCOUNT_HERE",
˓→"permission":"active"}]}]}'
1.11.8 Test
This test will use a regular EOS account instead of a LiquidAccount, to use a LiquidAccount, visit the LiquidAccount
section for how to send a transaction.
First install the dapp-client
npm install -g @liquidapps/dapp-client
44 Chapter 1. Developers
LiquidApps
(async () => {
const service = await (await getClient()).service('storage', "YOUR_ACCOUNT_HERE");
const data = Buffer.from("a great success", "utf8");
const key = "YOUR_ACTIVE_PRIVATE_KEY_HERE";
const permission = "active";
const response = await service.upload_public_file(
data,
key,
permission
);
console.log(`response uri: ${response.uri}`);
})().catch((e) => { console.log(e); });
# node test.js
response uri: ipfs://IPFS_URI_HERE
This will return the IPFS URI where the content can be fetched.
Add the URI to the end of the IPFS gateway: https://ipfs.io/ipfs/IPFS_URI_HERE, and you will see “a
great success”.
The DAPP Network uses custom event logs to communicate between consumer contracts and the DAPP Service
Providers (specialized EOSIO nodes running the DAPP Network logic and servicing requests). For this reason any
print statements added to a contract which utilizes a DAPP Network service must end with a newline (\n) in order to
not interfere with the event parsing.
For example:
print("Hello World!");
print("\n");
The DAPP Network utilizes a series of macros and service actions to perform different logic. Many of the macros use
a special syntax to interact with the DAPP Service Providers.
In this portion of the docs we’ll have a look at the macros associated with the DAPP Network’s core services (beta and
above). We’ll also explore some of the macros exposed by the dappservices contract (core contract to the DAPP
Network that handles staking, the DAPP token, and packages). This is intended to be an additional reading piece to
the getting started sections.
• dappservices
• vRAM
• LiquidAccounts
• LiquidHarmony (oracles)
• LiquidScheduler (cron)
1.13.1 dappservices
CONTRACT_START() | code
/**
* Wraps the eosio::contract class and provides the DAPP service actions needed for
˓→each service utilized as well as a specified CONTRACT_NAME. Intended to be used
˓→with CONTRACT_END.
*
* @param CONTRACT_NAME - defines smart contract's name
* @param DAPPSERVICES_ACTIONS - specifies DAPP Service actions that must be
˓→included to perform a service
*
* @return eosio::contract class with DAPP service actions defined under
˓→DAPPSERVICES_ACTIONS() and CONTRACT_NAME
*
* Example:
*
* @code
* #define DAPPSERVICES_ACTIONS() \
* XSIGNAL_DAPPSERVICE_ACTION \
* ORACLE_DAPPSERVICE_ACTIONS
*
* #define CONTRACT_NAME() oracleconsumer
*
* CONTRACT_START()
* @endcode
*/
#define CONTRACT_START() \
CONTRACT CONTRACT_NAME() : public eosio::contract { \
using contract::contract; \
public: \
DAPPSERVICES_ACTIONS()
CONTRACT_END() | code
/**
* Generates the EOSIO_DISPATCH_SVC list of actions for a smart contract. Intended
˓→to be used with CONTRACT_START.
*
* @param CONTRACT_NAME - contract name for eosio smart contract
* @param methods - list of actions to be included in the smart contract's ABI
(continues on next page)
46 Chapter 1. Developers
LiquidApps
#define CONTRACT_END(methods) \
}; \
EOSIO_DISPATCH_SVC(CONTRACT_NAME(),methods)
1.13.2 vRAM
dapp::multi_index | code
/**
* DAPP Network version of the eosio::multi_index container. Enables storage of
˓→information in IPFS (vRAM) when not needed in RAM. When data is warmed up, it is
˓→checked against the merkle root stored on-chain to ensure integrity and prevent a
*
* @param {name} code - account that owns table
* @param {uint64_t} scope - scope identifier within the code hierarchy
* @param {uint32_t} [shards=1024] - amount of shards to include for each table
* @param {buckets_per_shard} [buckets_per_shard=64] - number of buckets to use per
˓→shard
*
* @return advanced_multi_index container
*
* Notes
* - by utilizing the cleanup_delay param, data persists to RAM and can be used
˓→until committed. One use case for this is a session based application where a user
˓→does not need their data committed to RAM after each transaction. The cleanup_
˓→delay is reset each time a user uses the data. If a user is inactive for say 120
˓→seconds, then their data can be committed. Utilizing the cleanup_delay also
˓→prevents the latency associated with warming up data into RAM from vRAM (IPFS).
* - by selecting pin_shards = true, the shards will not be evicted from the
˓→ipfsentry table after the transaction that required the data is run
*
*
* Example:
*
* @code
* TABLE testindex {
* uint64_t id;
(continues on next page)
TABLE testindex {
uint64_t id;
uint64_t sometestnumber;
uint64_t primary_key()const {return id;}
};
48 Chapter 1. Developers
LiquidApps
// increment revision number, reset shards and buckets_per_shard params and next_
˓→ available_key in vconfig table
[[eosio::action]] void testclear() {
testindex_t testset(_self,_self.value, 1024, 64, false, false, 0);
testset.clear();
}
1.13.3 LiquidAccounts
/**
* LiquidAccounts use a payload syntax in order to pass params. This payload is
˓→setup as a struct and uses the EOSLIB_SERIALIZE to create the payload type
*
* @param {name} vaccount - vaccount that owns table
*
* Notes
* - primary key for the vaccount payload table must be "vaccount" for client side
˓→library support
*
* Example:
*
* @code
* struct dummy_action_hello {
* name vaccount;
* uint64_t b;
* uint64_t c;
*
* EOSLIB_SERIALIZE( dummy_action_hello, (vaccount)(b)(c) )
* };
*
* [[eosio::action]] void hello(dummy_action_hello payload) {
* ...
* }
* @endcode
*/
VACCOUNTS_APPLY | code
/**
* LiquidAccounts use the VACCOUNTS_APPLY macro to map which payload structs are
˓→associated with which actions. It also defines the LiquidAccount action.
(continues on next page)
require_vaccount | code
/**
* LiquidAccounts use the require_vaccount macro in place of the require_auth macro
˓→for authenticating a LiquidAccount against the key assigned when calling regaccount
*
* @param {name} - vaccount from payload
*
* Example:
*
* @code
* require_vaccount(payload.vaccount);
* @endcode
*/
VACCOUNTS_DELAYED_CLEANUP | code
/**
* LiquidAccounts use the VACCOUNTS_DELAYED_CLEANUP time in seconds to prevent data
˓→from being committed to IPFS from RAM.
*
* @param {uint32_t} VACCOUNTS_DELAYED_CLEANUP - time delay in seconds before data
˓→is removed from RAM and committed to vRAM (IPFS)
*
* Notes
* - VACCOUNTS_DELAYED_CLEANUP is intended to allow DAPPs to operate in a session
˓→based way. Data persists to RAM for the time specified to avoid the warmup process
˓→associated with vRAM data. After the user has become inactive, the data is
˓→committed.
*
* Example:
*
* @code
* #define VACCOUNTS_DELAYED_CLEANUP 120
(continues on next page)
50 Chapter 1. Developers
LiquidApps
1.13.4 LiquidHarmony
geturi | code
/**
* LiquidHarmony uses the geturi action to perform an oracle request
*
* @param {std::vector<char>} uri - hex conversion of URL syntax to perform an
˓→oracle request
TABLE oracleentry { \
uint64_t id; \
std::vector<char> uri; \
std::vector<provider_result> results; \
checksum256 hash_key() const { return hashData(uri); } \
uint64_t primary_key()const { return id; } \
}; \
typedef eosio::multi_index<"oracleentry"_n, oracleentry, indexed_by<"byhash"_n, const_
˓→mem_fun<oracleentry, checksum256, &oracleentry::hash_key>>> oracleentries_t; \
1.13.5 LiquidScheduler
schedule_timer | code
/**
* LiquidScheduler uses the schedule_timer macro to schedule a cron action on chain
˓→by adding a timer to the timerentry singleton
*
* @param {name} timer - account name to scope the timer within
* @param {std::vector<char>} payload - payload to be accessed within the timer_
˓→callback function in the consumer contract
TABLE timerentry { \
int64_t set_timestamp = 0; \
int64_t fired_timestamp = 0; \
};\
typedef eosio::singleton<"timer"_n, timerentry> timers_def;\
52 Chapter 1. Developers
LiquidApps
return; \
current_timer.fired_timestamp = eosio::current_time_point().time_since_epoch().
˓→count(); \
timers.set(current_timer, current_receiver()); \
if(!timer_callback(timer, payload, seconds)) \
return; \
schedule_timer(timer, payload, seconds);\
} \
remove_timer | code
/**
* LiquidScheduler uses the remove_timer macro to remove a timer from the
˓→timerentry singleton
*
* @param {name} timer - account name to scope the timer within
* @param {std::vector<char>} payload - payload to be accessed within the timer_
˓→callback function in the consumer contract
timer_callback | code
/**
* LiquidScheduler uses the timer_callback to run the cron logic within the
˓→consumer contract
*
* @param {name} timer - account name to scope the timer within
* @param {std::vector<char>} payload - payload to be accessed within the timer_
˓→callback function in the consumer contract
Unit testing with Zeus is highly customizable and easy to configure. The following example explains how to use the
main helper functions to write your own test.
in tests/mycontract.spec.js
require('mocha');
const { assert } = require('chai'); // Using Assert style
const { getCreateKeys } = require('../extensions/helpers/key-utils');
const getDefaultArgs = require('../extensions/helpers/getDefaultArgs');
const { getTestContract } = require('../extensions/tools/eos/utils');
const artifacts = require('../extensions/tools/eos/artifacts');
const deployer = require('../extensions/tools/eos/deployer');
const { genAllocateDAPPTokens, readVRAMData } = require('../extensions/tools/eos/dapp-
˓→services');
54 Chapter 1. Developers
LiquidApps
before(done => {
(async () => {
try {
/*** DISPLAY NAME FOR TEST, REPLACE 'coldissue' WITH ANYTHING ***/
it('coldissue', done => {
(async () => {
try {
done();
} catch (e) {
done(e);
}
})();
});
/*** USE it.skip TO CONTINUE WITH UNIT TEST IF TEST FAILS ***/
it.skip('it.skip does not assert and continues test if fails' ...
});
56 Chapter 1. Developers
LiquidApps
getCreateKeys | Code
/**
* @param account - account name to generate or fetch keys for
*/
artifacts | Code
The artifacts helper pulls the relevant contract files, such as the wasm / ABI, to be used within the unit test.
/**
* @param f - contract name within the /contracts/eos directory
*/
deployer | Code
The deployer function deploys a contract to an account based on the contract files and the account name passed.
You may also pass your own args, if not specified, the getDefaultArgs() function will be passed.
/**
* @param contract - contract file name to deploy
* @param account - account name to deploy contract to
* @param [args=getDefaultArgs()] - arguments to be used for configuring the network
˓→'s settings
*/
genAllocateDAPPTokens | Code
The genAllocateDAPPTokens function allocates DAPP tokens to the specified contract provided. It also issues,
selects a package, stakes, and updates auth to include eosio.code.
/**
* @param deployedContract - deployed contract
(continues on next page)
readVRAMData | Code
The readVRAMData function makes a vRAM get table row call by providing the contract, key, table, and
scope arguments.
/**
* @param contract - account name contract was deployed to
* @param key - primary key of the dapp::multi_index container
* @param table - table name as specified in the ABI
* @param scope - scope of dapp::multi_index container to read from
*/
getTestContract | Code
The getTestContract function creates an EOSJS instance to be used for sending EOS transactions.
/**
* @param code - account name to use in setting up
*/
58 Chapter 1. Developers
LiquidApps
zeus test -c
DSPs who have registered their service packages may be found in the package table under the dappservices account
on every supported chain.
DSP Portals for viewing/interacting with packages:
• DSP HQ
• Bloks.io
• EOS Nation
• Malta Block
• Mission Control
• Aloha EOS
• MinerGate
• package_period - period of the package before restaking is required. Upon restaking the QUOTA and package
period are reset.
• min_stake_quantity - the minimum quantity of DAPP and/or DAPPHDL (Air-HODL) tokens to stake to re-
ceive the designated amount of QUOTA for the specified package_period
• min_unstake_period - period of time required to pass before refund action can be called after unstake com-
mand is executed
• enabled - bool if the package is available or not
export PROVIDER=someprovider
export PACKAGE_ID=providerpackage
export MY_ACCOUNT=myaccount
# Stake your DAPP to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappservices stake "[\"$MY_ACCOUNT\",\"$PROVIDER\",
˓→\"$SERVICE\",\"50.0000 DAPP\"]" -p $MY_ACCOUNT@active
If you were a holder of the EOS token on February 26th, 2019 then you should have a balance of DAPPHDL tokens.
These tokens possess the ability to 3rd party stake and unstake tokens throughout the duration of the AirHODL, until
February 26th 2021.
# Stake your DAPPHDL to the DSP that you selected the service package for:
cleos -u $DSP_ENDPOINT push action dappairhodl1 stake "[\"$MY_ACCOUNT\",\"$PROVIDER\",
˓→\"$SERVICE\",\"50.0000 DAPPHDL\"]" -p $MY_ACCOUNT@active
The amount of time that must pass before an unstake executes a refund action and returns DAPP or DAPPHDL tokens
is either the current time + the minimum unstake time as stated in the package table, or the end of the current package
period, whichever is greater.
60 Chapter 1. Developers
LiquidApps
# In case unstake deferred trx fails, you can manually refund the unstaked tokens:
cleos -u $DSP_ENDPOINT push action dappairhodl1 refund "[\"$MY_ACCOUNT\",\"$PROVIDER\
˓→",\"$SERVICE\"]" -p $MY_ACCOUNT@active
Please note: withdrawing your DAPPHDL tokens immediately makes you ineligible for further vesting and forfeits
all your unvested tokens. This action is irrevocable. Vesting ends February 26th 2021. Also, you must hold DAPP
token before executing this action. If you do not, use the open action below to open a 0 balance.
# Withdraw
cleos -u $DSP_ENDPOINT push action dappairhodl1 withdraw "[\"$MY_ACCOUNT\"]" -p $MY_
˓→ACCOUNT@active
In the dappairhodl1 contract under the accounts table, enter your account as the scope to retrieve its information.
# Refresh accounts table data
cleos -u $DSP_ENDPOINT push action dappservices refresh "[\"$MY_ACCOUNT\"]" -p $MY_
˓→ACCOUNT@active
Third parties may stake to a DSP package on behalf of a DAPP by calling the staketo and unstaketo actions.
In order for a DAPP to select a new package after third parties have staked to them, all third party stakes must be
removed.
The following two actions remove third party stakes, preselectpkg allows users to be removed in batches by sup-
plying a depth parameter to indicate how many accounts to remove at a time. The second action is retirestakes
which allows for the removal of specific third party stakes from a list of delegators account names.
Third party stakers can be identified by supplying the ID of the accountext table entry that matches the account,
provider, service, and package (or pending package) selected by the account being staked to as the scope of the
stakingext table, for example: 150.
Examples:
˓→"cronservices\",\"delegators\":["dappservice2","natdeveloper","oracletest22"]}" -p
˓→$MY_ACCOUNT
˓→"symcode\":\"DAPP\"}" -p $MY_ACCOUNT
preselectpkg allows the DAPP to simply supply a depth (number of third party stakes) to remove per tx ordered
by the ID of “payer”. The DAPP may simply execute this as many times as required until no more third party stakes
remain. If a depth that is too deep is selected (for example, 100) the trx will simply fail, and a smaller depth can be
selected. This method requires no external knowledge of who has staked to the account.
retirestakes is a more explicit and selective method for a DAPP. A list of third party stake payers (name[]
delegators) can be provided. If the list is too large, the tx may time out. In order to discover who has staked to the
DAPP’s package the following steps can be utilized:
1. Determine the id of their package’s accountext table entry. accountext entries all use the scope DAPP. The
correct entry is the entry that has that same account, service, provider, and package (or pending_package) as the
selected package. bloks.io accountext table
2. Find the stakingext entries, using the id from the accountext table as the scope. bloks.io stakingext
table
3. Each entry under this scope will have payers equal to the account names of the third parties. These payers can
be used to populate the delegators for the retirestakes action.
For both actions, if the depth is deeper than the number of stakes, or the delegators list includes payers that
haven’t actually staked, it will succeed gracefully, ignoring the erroneous entries and executing for the correct ones.
The dappairhodl1 contract is the exception to all of this. It does not get added to the stakingext table since
while it is a third party stake mechanically, it is essentially the same as a first party stake. We do not support third
party staking using AirHODL’d DAPP.
• regression-tests
• helloworld
• coldtoken
• airhodl
• airdrop
62 Chapter 1. Developers
LiquidApps
• bancor-extensions
• cardgame
• dapp-services-deploy
• templates-emptycontract-eos-cpp
• all-dapp-services
• sample-zeus-extension
• deepfreeze
• vgrab
• dapp
• game
• ide
• dgoods
• eoscraft
The gitignore ignores all extensions at the moment, in the future you will be able to install those extensions with zeus
install, but until that time just ignore the node_modules folder
1.18.1 dsp-service.json
• name - define the simplest version of your DSP service, this is used for DSPs to register the service with the
zeus register dapp-service-provider-package. It is the PACKAGE env variable
• port - select a port for your service to run on, ensure the other services don’t overlap as each service must have
a unique port
• prettyName - what the service will be officially referred to (LiquidAccounts, vRAM, etc..)
• stage - Work in Progress (WIP), Alpha, Beta, Stable
{
"name": "dsp-service",
"port": 13150,
"prettyName": "Liquid...",
"stage":"WIP or Alpha, or BETA, or Stable",
"version": "0.9",
"description": "Allows interaction with contract without a native EOS Account",
"contract": "account_service_contract_is_deployed_on",
"commands": {
"example_command": {
"blocking (true = syncronous, false = async)": false,
"request": {
},
"callback": {
"payload": "std::vector<char>",
"sig": "eosio::signature",
"pubkey": "eosio::public_key"
},
"signal": {
"sig": "eosio::signature",
"pubkey": "eosio::public_key"
}
}
}
}
• search
64 Chapter 1. Developers
CHAPTER 2
DSPs
2.1.1 Overview
Overview
Architecture
2.1.2 Prerequisites
Account
2.1.3 Deploy
EOSIO Node
IPFS Node
PostgreSQL Database
DSP Service Node
2.1.4 Configuration
Packages
Testing
65
LiquidApps
Claim
Upgrade
Replay Contract
Cleanup IPFS Entries
Consumer Permissions
2.2 Overview
2.2.1 Articles
2.2.2 Videos
• Developer Explains - Decentralized Dapp Scaling w/ IPFS! How LiquidApps Dapp Service Providers Work
• EOS Weekly - The LiquidApps Game-Changer
• EOS Weekly - Unlimited DSP Possibilities
66 Chapter 2. DSPs
LiquidApps
2.3 Architecture
A DSP consists of an EOS state history node (non block producing node without a full history setup), an IPFS cluster,
a PostgreSQL Database, and a DSP API endpoint. All 4 of these operations may be run on the same machine or
separately. All necessary settings may be found in the config.toml file.
• EOS state history node - to run a DSP requires running a non block producing EOS node. A full
history node is also not required. The EOS node is configured with a backend storage mechanism:
state_history_plugin.
• IPFS Cluster node - the IPFS cluster stores all vRAM information so that it may be loaded into RAM as a
caching mechanism. The InterPlanetary File System is a protocol and peer-to-peer network for storing and
sharing data in a distributed file system. IPFS uses content-addressing to uniquely identify each file in a global
namespace connecting all computing devices. The documentation shows how to setup a local IPFS cluster, but
you may also configure an external IPFS cluster in the config.toml file.
• PostgreSQL Database - a PostgreSQL database is utilized to prevent duplicate transactions by creating, updating,
and retrieving transaction data.
• DSP API - the DSP API is responsible for performing all DAPP service logic such as a vRAM
get_table_row call, parsing and sending a LiquidAccount transaction, servicing an oracle call, etc.
In the config.toml file in the DSP Node Setup you can configure the state_history_plugin.
You can also configure the HEAD_BLOCK to sync demux from. If you experience any issues with demux syncing from
an older block, you may try syncing demux at the head block by finding it at bloks.io and setting it to head_block.
[demux]
backend = "state_history_plugin"
2.5 Account
2.5.1 Prerequisites
Mainnet
2.3. Architecture 67
LiquidApps
Fiat:
• EOS Account Creator
• EOS Lynx
• Scatter
Bitcoin/ETH/Bitcoin Cash/ALFAcoins:
• ZEOS
Kylin
Create an account
# Create a new available account name (replace 'yourdspaccount' with your account
˓→name):
export DSP_ACCOUNT=yourdspaccount
curl http://faucet-kylin.blockzone.net/create/$DSP_ACCOUNT > keys.json
curl http://faucet-kylin.blockzone.net/get_token/$DSP_ACCOUNT
export DSP_PRIVATE_KEY=`cat keys.json | jq -e '.keys.active_key.private'`
export DSP_PUBLIC_KEY=`cat keys.json | jq -e '.keys.active_key.public'`
# Create wallet
cleos wallet create --file wallet_password.pwd
A non block / non full history node is required for the DSP API to interact with. This node may be hosted with the
rest of the DSP architecture or standalone.
68 Chapter 2. DSPs
LiquidApps
2.6.2 Prerequisites
• jq
• wget
• curl
Ubuntu 18.04
FILENAME=eosio_$VERSION-1-ubuntu-18.04_amd64.deb
INSTALL_TOOL=apt
Ubuntu 16.04
FILENAME=eosio_$VERSION-1-ubuntu-16.04_amd64.deb
INSTALL_TOOL=apt
Fedora
FILENAME=eosio_$VERSION-1.fc27.x86_64.rpm
INSTALL_TOOL=yum
Centos
FILENAME=eosio_$VERSION-1.el7.x86_64.rpm
INSTALL_TOOL=yum
2.6.4 Install
wget https://github.com/EOSIO/eos/releases/download/v$VERSION/$FILENAME
sudo $INSTALL_TOOL install ./$FILENAME
#cleanup
rm -rf $HOME/.local/share/eosio/nodeos || true
#create dirs
mkdir $HOME/.local/share/eosio/nodeos/data/blocks -p
mkdir $HOME/.local/share/eosio/nodeos/data/snapshots -p
mkdir $HOME/.local/share/eosio/nodeos/config -p
Snapshots
If you would like an up to date snapshot, please visit: snapshots.eosnation.io and find the latest snapshot for the
chain you are using. You will want to unpack the file and store it here with the following file name: $HOME/
.local/share/eosio/nodeos/data/snapshots/boot.bin. EOS Node tools many also be used for
mainnet: https://eosnode.tools/snapshots
Kylin
URL="http://storage.googleapis.com/eos-kylin-snapshot/snapshot-2019-06-10-09(utc)-
˓→0312d3b9843e2efa6831806962d6c219d37200e0b897a0d9243bcab40b2b546b.bin"
P2P_FILE=https://raw.githubusercontent.com/cryptokylin/CryptoKylin-Testnet/master/
˓→fullnode/config/config.ini
GENESIS=https://raw.githubusercontent.com/cryptokylin/CryptoKylin-Testnet/master/
˓→genesis.json
CHAIN_STATE_SIZE=256000
wget $URL -O $HOME/.local/share/eosio/nodeos/data/snapshots/boot.bin
Jungle
bzip2 -d ./snapshot-2020-01-09-15-jungle.bin.bz2
mv snapshot-2020-01-09-15-jungle.bin $HOME/.local/share/eosio/nodeos/data/snapshots/
˓→boot.bin
P2P_FILE=https://validate.eosnation.io/jungle/reports/config.txt
GENESIS=https://raw.githubusercontent.com/EOS-Jungle-Testnet/Node-Manual-Installation/
˓→master/genesis.json
CHAIN_STATE_SIZE=256000
Mainnet
URL="https://s3.eu-central-1.wasabisys.com/eosnodetools/snapshots/snap_2019-12-15-13-
˓→00.tar.gz"
P2P_FILE=https://eosnodes.privex.io/?config=1
GENESIS=https://raw.githubusercontent.com/CryptoLions/EOS-MainNet/master/genesis.json
CHAIN_STATE_SIZE=16384
cd $HOME/.local/share/eosio/nodeos/data
wget $URL -O - | tar xvz
(continues on next page)
70 Chapter 2. DSPs
LiquidApps
2.6.6 Configuration
cd $HOME/.local/share/eosio/nodeos/config
# download genesis
wget $GENESIS
# config
cat <<EOF >> $HOME/.local/share/eosio/nodeos/config/config.ini
agent-name = "DSP"
http-server-address = 0.0.0.0:8888
p2p-listen-endpoint = 0.0.0.0:9876
blocks-dir = "blocks"
abi-serializer-max-time-ms = 3000
max-transaction-time = 150000
wasm-runtime = eos-vm
eos-vm-oc-enable = true
reversible-blocks-db-size-mb = 1024
contracts-console = true
p2p-max-nodes-per-host = 1
allowed-connection = any
max-clients = 100
sync-fetch-span = 500
connection-cleanup-period = 30
http-validate-host = false
access-control-allow-origin = *
access-control-allow-headers = *
access-control-allow-credentials = false
verbose-http-errors = true
http-threads=8
net-threads=8
trace-history-debug-mode = true
trace-history = true
plugin = eosio::producer_plugin
plugin = eosio::chain_plugin
plugin = eosio::chain_api_plugin
plugin = eosio::net_plugin
plugin = eosio::state_history_plugin
state-history-endpoint = 0.0.0.0:8887
chain-state-db-size-mb = $CHAIN_STATE_SIZE
EOF
2.6.7 Run
You will know that the node is fully synced once you see blocks being produced every half second at the head block.
You can match the block number you are seeing in the nodeos logs to what bloks.io is indicating as the head block on
the chain you are syncing (mainnet, Kylin etc). Once you have confirmed that it is synced press CTRL+C once, wait
for the node to shutdown and proceed to the next step.
2.6.8 systemd
2.6.9 Optimizations
2.7 IPFS
The InterPlanetary File System is a protocol and peer-to-peer network for storing and sharing data in a distributed file
system. IPFS uses content-addressing to uniquely identify each file in a global namespace connecting all computing
devices. The DSPs utilize this as the storage layer to request and serve information to and from vRAM <> RAM as a
caching solution.
2.7.1 Standalone
go-ipfs
72 Chapter 2. DSPs
LiquidApps
Hardware Requirements
Prerequisites
• golang
• systemd
Ubuntu/Debian
Centos/Fedora/AWS Linux v2
Install
sudo su -
VERS=0.4.22
DIST="go-ipfs_v${VERS}_linux-amd64.tar.gz"
wget https://dist.ipfs.io/go-ipfs/v$VERS/$DIST
tar xvfz $DIST
rm *.gz
mv go-ipfs/ipfs /usr/local/bin/ipfs
exit
Configure systemd
sudo su -
ipfs init
ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001
ipfs config Addresses.Gateway /ip4/0.0.0.0/tcp/8080
cat <<EOF > /lib/systemd/system/ipfs.service
[Unit]
Description=IPFS daemon
After=network.target
[Service]
ExecStart=/usr/local/bin/ipfs daemon
Restart=always
[Install]
WantedBy=multi-user.target
EOF
exit
2.7. IPFS 73
LiquidApps
Adding Peers
To connect with your peers you may open port 4001 to the selected IPs that you wish to communicate with or open
the port to all addresses.
Bootstrap peers default to IPFS nodes provided by the core development team. They are scattered across the world.
These peers are what your IPFS node will initially monitor upon startup. You may add our mainnet and kylin testnet
IPFS nodes with the following commands:
# kylin
Swarm peers are addresses that the local daemon will listen on for connections from other IPFS peers. They are what
your IPFS node will look to first when requesting a file that is not cached locally. Both your node as well as the node
you are trying to connect to must run the following commands:
# kylin
Peers have a tendency to disconnect from each other if not reconnected manually periodically, so to combat this, you
may add the following two files to periodically reconnect to your swarm peers.
sudo su -
cat <<EOF > /lib/systemd/system/gateway-connector.service
[Unit]
Description=Job that periodically connects this IPFS node to the gateway node
[Service]
ExecStart=/usr/local/bin/ipfs swarm connect <ADD_MULTIPLE_CONNECTIONS_HERE_SPACE_
˓→SEPARATED> # /ip4/52.70.167.190/tcp/4001/ipfs/
˓→QmZ5gLTZwvfD5DkbbaFFX4YJCi7f4C5oQAgq8qpjL8S1ur /ip4/34.224.152.33/tcp/4001/ipfs/
˓→QmcCX4b3EF3eXaDe5dgxTL9mXbyci4FwcJAjWqpub5vCXM
Environment="IPFS_PATH=/root/.ipfs"
EOF
exit
sudo su -
cat <<EOF > /lib/systemd/system/gateway-connector.timer
[Unit]
(continues on next page)
74 Chapter 2. DSPs
LiquidApps
systemctl list-timers
You should see an entry for your gateway connector service. You can also check the status of its last execution attempt
by running:
Running a private IPFS network is possible by removing all default IPFS bootstrap peers and only adding those of
your private network.
ipfs bootstrap rm all - Remove all peers from the bootstrap list
2.7.2 Cluster
IPFS-Cluster | Documentation
IPFS is designed so that a node only stores files locally that are specifically requested. The following is one way of
populating a new IPFS node with all existing files from a pre-existing node.
To do so, first create a secret from node0, the original node, then share that secret with node1, the node you want
to bootstrap from node0. Then node1 runs the bootstrap command specifying the cluster’s address and setting the
CLUSTER_SECRET as an env variable.
node0
2.7. IPFS 75
LiquidApps
• ipfs-cluster-service init
• ipfs-cluster-service daemon
node0
• if you want to remove a peer after the bootstrapping is complete, the following command will do that and shut
down the IPFS cluster
• ipfs-cluster-ctl peers rm QmYFYwnFUkjFhJcSJJGN72wwedZnpQQ4aNpAtPZt8g5fCd
A PostgreSQL databse is utilized to prevent duplicate DSP transactions by creating, getting, and updating service
events as needed. An external database can be set by ensuring the node_env variable in the config.toml
file is set to production. The database settings may be specified with the url variable, e.g., postgres://
user:[email protected]:5432/dbname.
2.8.1 config.toml:
[database]
url = "postgres://user:[email protected]:5432/dbname"
node_env = "production"
76 Chapter 2. DSPs
LiquidApps
sudo su - postgres
psql
CREATE DATABASE dsp;
CREATE USER dsp WITH ENCRYPTED PASSWORD 'Put-Some-Strong-Password-Here';
GRANT ALL PRIVILEGES ON DATABASE dsp to dsp;
sudo su - postgres
psql
\l # to list database and find your DB name, mine is "dsp"
\c dsp #to connect to the DB
drop table "Settings";
drop table "ServiceRequests";
<CTRL> d # exit
2.9.1 Prerequisites
• git
Linux
sudo su -
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
export NVM_DIR="${XDG_CONFIG_HOME/:-$HOME/.}nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
# latest is 10.17.0 which has issues
nvm install 10.16.3
nvm use 10.16.3
exit
Ubuntu/Debian
Centos/Fedora/AWS Linux:
2.9.2 Install
sudo su -
npm install -g pm2
npm install -g @liquidapps/dsp --unsafe-perm=true
exit
Any changes to the config.toml file will require setup-dsp to be run again. Link to sample-config.
toml
sudo su -
mkdir ~/.dsp
cp $(readlink -f `which setup-dsp` | xargs dirname)/sample-config.toml ~/.dsp/config.
˓→toml
nano ~/.dsp/config.toml
exit
sudo su -
setup-dsp
systemctl stop dsp
systemctl start dsp
systemctl enable dsp
exit
2.9.5 Logs
There are several log files when it comes to the DAPP Service Providers. The logs folder can be
found in the directory the dsp software was installed in. Each service has its own log file, for example:
DSP_NAME_HERE-ipfs-dapp-service-node-2020-03-03.log. The service file will log the service re-
lated information.
There is also a demux and dapp service node log DSP_NAME_HERE-demux-2020-03-03.log,
DSP_NAME_HERE-dapp-services-node-2020-03-03.log. The demux log tracks the interaction
with the state history node, listening for relevant information for the DSP to act upon. The dapp service node log is
the first point of contact when sending a transaction to the DSP, this is the gateway that fields requests to the correct
service files, to the nodeos RPC API in the case of say pushing a transaction or fetching a table row, or using the
/v1/dsp/version endpoint for returning the current version of the DSP software on the node.
Finally for each chain a DSP supports with LiquidX there is an additional dapp service node and
demux log DSP_NAME_HERE-CHAIN_NAME_HERE-dapp-services-node-2020-03-03.log
DSP_NAME_HERE-CHAIN_NAME_HERE-demux-2020-03-03.log.
sudo su -
cd $(readlink -f `which setup-dsp` | xargs dirname)
cd logs
exit
78 Chapter 2. DSPs
LiquidApps
pm2 logs can be used to ensure that there are no issues outside of the logging statements used. For example, if a
javascript file was improperly formatted, that error may show up in pm2 logs.
sudo su -
pm2 logs
exit
Output sample:
2.10 Packages
2.10.1 Register
{
"name": "acme DSP",
"website": "https://acme-dsp.com",
"code_of_conduct":"https://...",
"ownership_disclosure" : "https://...",
"email":"[email protected]",
(continues on next page)
2.10. Packages 79
LiquidApps
{
"name": "Package 1",
"description": "Best for low vgrabs",
"dsp_json_uri": "https://acme-dsp.com/dsp.json",
"logo":{
"logo_256":"https://....",
"logo_1024":"https://....",
"logo_svg":"https://...."
},
"service_level_agreement": {
"availability":{
"uptime_9s": 5
},
"performance":{
"95": 500
}
},
"pinning":{
"ttl": 2400,
"public": false
},
"locations":[
{
"name": "Atlantis",
"country": "ATL",
"latitude": 2.082652,
"longitude": 1.781132
}
(continues on next page)
80 Chapter 2. DSPs
LiquidApps
Register Package
export MIN_STAKE_QUANTITY="10.0000"
# package period is in seconds, so 86400 = 1 day, 3600 = 1 hour
export PACKAGE_PERIOD=86400
# the time to unstake is the greater of the package period remaining and the minimum
˓→unstake period, which is also in seconds
export MIN_UNSTAKE_PERIOD=3600
# QUOTA is the measurement for total actions allowed within the package period to be
˓→processed by the DSP. 1.0000 QUOTA = 10,000 actions. 0.0001 QUOTA = 1 action
export QUOTA="1.0000"
export DSP_ENDPOINT=https://acme-dsp.com
# package json uri is the link to your package's information, this is customizable
˓→without a required syntax
export PACKAGE_JSON_URI=https://acme-dsp.com/package1.dsp-package.json
Or in cleos:
2.10. Packages 81
LiquidApps
export SERVICE=ipfsservice1
# zeus command automatically adds QUOTA / DAPP, so we must add it here
export QUOTA="1.0000 QUOTA"
export MIN_STAKE_QUANTITY="10.0000 DAPP"
export EOS_ENDPOINT=https://kylin-dsp-2.liquidapps.io # or mainnet: https://api.
˓→eosnewyork.io
˓→STAKE_QUANTITY\",\"min_unstake_period\":\"$MIN_UNSTAKE_PERIOD\",\"package_id\":\"
˓→$PACKAGE_ID\",\"package_json_uri\":\"$PACKAGE_JSON_URI\",\"package_period\":\"
˓→$PACKAGE_PERIOD\",\"provider\":\"$DSP_ACCOUNT\",\"quota\":\"$QUOTA\",\"service\":\"
˓→$SERVICE\"}}" -p $DSP_ACCOUNT
Currently only package_json_uri and api_endpoint are modifyable. To signal to DSP Portals / Developers
that your package is no longer in service, set your api_endpoint to null.
To modify package metadata: use the “modifypkg” action of the dappservices contract.
Using cleos:
cleos -u $DSP_ENDPOINT push action dappservices modifypkg "[\"$DSP_ACCOUNT\",\"
˓→$PACKAGE_ID\",\"ipfsservice1\",\"$DSP_ENDPOINT\",\"https://acme-dsp.com/modified-
˓→package1.dsp-package.json\"]" -p $DSP_ACCOUNT@active
The pricepkg action on the dappservices contract allows a DSP to set how much QUOTA to bill for per
action. For example, a DSP could decide to charge 0.0002 QUOTA per vRAM warmup. The default for each ac-
82 Chapter 2. DSPs
LiquidApps
tion is 0.0001 QUOTA. The billable actions for all services may be found in the zeus-sdk/boxes/groups/
services/SERVICE_NAME-dapp-service/models/dapp-services/SERVICE_NAME.json, for ex-
ample: vRAM.
• name provider - DSP name
• name package_id - package name
• name service - service name, e.g., ipfsservice1
• name action - action name, e.g., warmup, commit, geturi, etc
• uint64_t cost - QUOTA cost per action, e.g., 1 = 0.0001 QUOTA, 5, = 0.0005 QUOTA, etc
2.11 Testing
Please note, if you wish to test on the mainnet, this will require the purchase of DAPP tokens or the use of DAPPHDL
tokens (Air-HODL). In the case of Kylin, we provide a DAPP token faucet.
• Kylin
• Mainnet
Install Zeus:
˓→":{\"actor\":\"$ACCOUNT\",\"permission\":\"eosio.code\"},\"weight\":1}]}" owner -p
˓→$ACCOUNT@active
(continues on next page)
2.11. Testing 83
LiquidApps
export MIN_STAKE_QUANTITY=
# select DSP package
cleos -u $DSP_ENDPOINT push action dappservices selectpkg "{\"owner\":\"$ACCOUNT\",\
˓→"provider\":\"$DSP_ACCOUNT\",\"service\":\"$DSP_SERVICE\",\"package\":\"$DSP_
˓→PACKAGE\"}" -p $ACCOUNT
˓→QUANTITY\"}" -p $ACCOUNT
˓→QUANTITY\"}" -p $ACCOUNT
# create coldtoken
cleos -u $DSP_ENDPOINT push action $ACCOUNT create "{\"issuer\":\"$ACCOUNT\",\
˓→"maximum_supply\":\"1000000000 TEST\"}" -p $ACCOUNT
# with curl:
curl http://$DSP_ENDPOINT/v1/dsp/ipfsservice1/get_table_row -d '{"contract":"CONTRACT_
˓→ACCOUNT","scope":"SCOPE","table":"TABLE_NAME","key":"TABLE_PRIMARY_KEY"}' | python -
˓→m json.tool
84 Chapter 2. DSPs
LiquidApps
Transfer:
˓→$ACCOUNT
pm2 logs
Claim
As a DSP, you will want the ability to replay a contract’s vRAM (IPFS) related transactions to load that data into your
IPFS cluster. We provide a file that does just that replay-contract.js.
To do this you will need to sign up for an API key from dfuse.io, you can select the Server to Server option from the
dropdown when creating it. Dfuse offers free keys that last 24 hours, so there’s no need to pay.
There are some mandatory and optional environment variables.
2.13.1 Mandatory:
export DFUSE_API_KEY=
# contract to replay
export CONTRACT=
export NODEOS_CHAINID=
˓→"aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906" # < mainnet |
2.13.2 Optional:
export LAST_BLOCK= # defaults to 35000000, this is the last block to sync from, find
˓→the first vRAM transaction for the contract and set the block before it
Sometimes IPFS or Oracle entries are not evicted from a developer’s contract due to the DSP experiencing un-
predictable behavior. This causes the developer’s smart contract RAM supply to increase as the ipfsentry /
oracleentry table rows are not evicted. If this happens, you may run the cleanup.js file with the following envi-
ronment variables:
The cleanup script will auto detect which table to cleanup ipfsentry or oracleentry depending on which one
is present on the contract. If both are set, you can use the TABLE env variable to specify which to cleanup.
2.14.1 Mandatory:
export CONTRACT=lqdportfolio
export DSP_ENDPOINT=http://kylin-dsp-2.liquidapps.io
2.14.2 Optional:
• CHUNK_SIZE represents the number of async requests for cleanups to send to the DSP at a time
86 Chapter 2. DSPs
LiquidApps
• TABLE type is auto detected based on the contract name (ipfs table: ipfsentry or oracle table:
oracleentry), if a contract has both tables, you will use this variable to target both
export CHUNK_SIZE= # defaults to 5
export TABLE= # defaults to ipfsentry or oracleentry by detecting from contract
The consumer of DSP services may optionally create permissions that allow the consumer to pay for all CPU, NET,
and RAM costs associated with the DSP services. This permission is optional. Without it, DSP services will continue
to operate normally.
Process
• The consuming contract creates a dsp permission under the active permission
• The dsp permissions requires that each provider used by the consumer must be added, for example:
provider1@active, provider2@active
• Each xaction required for the services used must be Link Authed to the dsp permission
with Bloks.io
Login with your account’s name using the cleos login option: https://kylin.bloks.io/wallet/permissions/advanced, and
the cleos command will be auto generated for you.
• click “Add New Permission
• click on permission to get it to open up
• permission name: dsp
• parent: active
• threshold: 1
• add as many DSP to the accounts section with the active permission (heliosslene - active, uuddlrlrbass - active,
etc)
• click save permission to have the cleos command auto generated
or Cleos
˓→ACCOUNT_HERE","permission":"dsp","parent":"active","auth":{"threshold":1,"keys":[],
˓→"accounts":[{"permission":{"actor":"DSP_ACCOUNT_NAME_HERE","permission":"active"},
2.15. Consumer Permissions
˓→"weight":1}],"waits":[]}},"authorization":[{"actor":"CONTRACT_ACCOUNT_HERE", 87
˓→"permission":"active"}]}]}'
LiquidApps
with Bloks.io
Go here: https://kylin.bloks.io/wallet/permissions/link
• login using your contract’s name for the cleos option
• Permission: dsp
• Contract name: CONTRACT_ACCOUNT_HERE, not the DSP name
• Contract action: xsignal
• Link Auth -> presto you have your cleos command
• You must repeat this process for all of the contract xactions you are using, you may find them by checking your
ABI or using a block explorer to view your actions
or Cleos
˓→ACCOUNT_HERE","code":"CONTRACT_ACCOUNT_HERE","type":"ACTION_NAME_HERE","requirement
˓→":"dsp"},"authorization":[{"actor":"CONTRACT_ACCOUNT_HERE","permission":"active"}]}
˓→]}'
For all new releases, please test on the Kylin testnet for at least one week before deploying to a production environment.
Link: sample-config.toml
sudo su -
systemctl stop dsp
systemctl stop ipfs
systemctl stop nodeos
# if changes to sample-config.toml syntax:
nano ~/.dsp/config.toml
pm2 del all
pm2 kill
npm uninstall -g @liquidapps/dsp
exit
# as USER
sudo chown ubuntu:ubuntu /home/ubuntu/.pm2/rpc.sock /home/ubuntu/.pm2/pub.sock
npm uninstall -g @liquidapps/dsp
sudo su -
(continues on next page)
88 Chapter 2. DSPs
LiquidApps
If a DSP is not updating properly, you may try pm2 restart all to restart all processes.
• search
90 Chapter 2. DSPs
CHAPTER 3
Liquidx
LiquidX enables DAPP Network services to be used between chains. A user can stake DAPP on the EOS mainnet for
an account on another eosio based chain.
This is accomplished by creating a set of mappings between accounts. DSPs and Users must create a 2 way mapping
where by they verify on the mainnet and on the chain in question that each account is linked. This topic is explored in
more detail in the docs to follow.
3.1.1 Docs:
To utilize the DAPP Network on another chain as a developer, a two way mapping must first be established between
the EOS mainnet account that is staking the DAPP to the service package and the account on the side chain that will
use the services. The point of this mapping is to verify that an account on the EOS mainnet has given permission to an
account on another chain to be able to bill on the EOS mainnet account’s behalf. This mapping must also be verified
on the new chain in question. A mainnet account can allow multiple new chain accounts to bill for services.
On the EOS mainnet this mapping is performed with the addaccount action on the liquidx.dsp account.
On the new chain in question, this is performed with the setlink action on the account that has deployed the
dappservicex.cpp contract (hopefully dappservicex for simplicity, but any account name can be used). To
figure out what account name this is, a DSP, BP, or community member can be asked.
91
LiquidApps
Guide:
• Smart Contract Steps
• Add DSP on New Chain
• Map Mainnet to New Chain
• Map New Chain to Mainnet
At the smart contract level, the liquidx box must be unboxed and #define LIQUIDX must be added at the top
of the smart contract which uses the DAPP Network services. In order for the compiler to know which network the
contract intends to be deployed on the --sidechain flag must be passed to zeus compile --sidechain
$SIDE_CHAIN_NAME.
Ensure that you add @eosio.code to the active permission level of the account. This can be done with the
--add-code flag on the cleos set account permission command.
The side chain name is the account on the EOS mainnet that has registered the chain. You may find what this contract
is by asking a DSP, a BP, or the chain team itself.
2 files must be added. One to the /liquidx/models/eosio-chains/ directory and one to the /liquidx/
models/liquidx-mappings/ directory.
/liquidx/models/liquidx-mappings/sidechain_name.dappservices.json - this maps the
dappservices account on the mainnet to the dappservicex account name on the new chain
• sidechain_name - EOS mainnet account that has registered the chain
• mainnet_account - dappservices account on EOS mainnet
• chain_account - dappservicex account on new chain - enter the sidechain_name as the scope for the
chainentry table, the dappservices_contract key will list the account name needed
{
"sidechain_name":"",
"mainnet_account":"dappservices",
"chain_account":""
}
92 Chapter 3. Liquidx
LiquidApps
npm i -g @liquidapps/zeus-cmd
zeus unbox liquidx
cd liquidx
export MY_CONTRACT_NAME=
zeus create contract $MY_CONTRACT_NAME
cd contracts/eos
# edit MY_CONTRACT_NAME.cpp
cd ../../
export SIDE_CHAIN_NAME=
zeus compile --sidechain $SIDE_CHAIN_NAME
cd contracts/eos
export EOS_ENDPOINT=
export ACCOUNT=
cleos -u $EOS_ENDPOINT set contract $ACCOUNT $MY_CONTRACT_NAME
To use a DSP on a new chain, the consumer must submit an adddsp command on the new chain on the account that
is hosting the dappservicex.cpp contract.
• owner {name} - name of consumer contract on new chain
• dsp {name} - dsp name on new chain (could be different from the mainnet DSP name), enter the mainnet DSP’s
account into the accountlink table on the liquidx.dsp contract to find this name
To map an EOS mainnet account to a new chain’s account, perform the addaccount action on the liquidx.dsp
account.
• owner {name} - name of account on the EOS mainnet staked to services
• chain_account {name} - name of account on new chain to use services
• chain_name {name} - account on mainnet that has registered the new chain, should be publicly available from
a representative of the chain (DSP, BP, community)
Example cleos command:
cleos -u https://nodes.get-scatter.com:443 push transaction '{"delay_sec":0,"max_cpu_
˓→usage_ms":0,"actions":[{"account":"liquidx.dsp","name":"addaccount","data":{"owner":
(continues on next page)
˓→"natdeveloper","chain_account":"liquidxcnsmr","chain_name":"mynewchainnn"},
˓→"authorization":[{"actor":"natdeveloper","permission":"active"}]}]}'
To map a new chain’s account to the EOS mainnet, navigate to the contract that has deployed the dappservicex.
cpp contract and perform the setlink action.
• owner {name} - name of account on the new chain to link, using services
• mainnet_owner {name} - name of account on mainnet, staking to services
Example cleos command:
˓→"liquidxcnsmr","mainnet_owner":"natdeveloper"},"authorization":[{"actor":
˓→"liquidxcnsmr","permission":"active"}]}]}'
In short you have run the adddsp and the setlink action on the new chain’s dappservicex account and the
addaccount action on the EOS mainet’s liquidx.dsp account.
The new chain account now has the ability to access any service staked to by the mainnet account.
LiquidX enables DSPs (DAPP Service Providers) to offer services on new chains. All existing and newly created
packages may be staked to and used by developers without any additional modifications.
To add a chain, a DSP must configure their DSP API’s config.toml file with the sidechain’s details then two way
map their EOS mainnet DSP account, the account that will be staked to and will receive rewards, to their sidechain
DSP account. This is done with the addaccount action on the mainnet liquidx.dsp account and adddsp on
the dappservicex.cpp contract on the new chain. As a note, the dappservicex.cpp contract’s account can
be called anything (hopefully dappservicex for simplicity), so the name must be found from the community.
To add a chain from an architecture perspective requires adding a new nodeos instance for that chain and having
another demux instance running on the DSP’s API endpoint. The nodeos instance can be run external to the DSP API.
There are two additional log files produced for the new chain. A new dapp-service-node log file for the new gateway
port and another demux log file.
See list of example chains to add here.
Guide:
• Editing config.toml file
• Push DSP account mapping action
In order to enable a new chain, a DSP must add the following to the config.toml environment variable file.
This is the file that holds the environment variables for your DSP’s API instance. Each sidechain will need a new
[sidechains.CHAIN_NAME] section. CHAIN_NAME - this is the account on the EOS mainnet that has registered
with the liquidx.dsp contract as the chain’s name. This name can be found from the block producers of the chain,
other DSPs, or the community.
94 Chapter 3. Liquidx
LiquidApps
[sidechains]
[sidechains.test1]
# dsp
dsp_port = 3116 # dsp port to run new chain's services on, this is the port
˓→developers will push to, must be unique per new chain
nodoes_latest = true # if using 2.0+ version of nodeos, true, if less than 2.0,
˓→false
demux_bypass_database_head_block = false
demux_max_pending_messages = 500 # amount of pending messages to add to the stack
˓→before disconnecting the demux websocket to allow pending messages to process
# sidechain
liquidx_contract = "liquidx.dsp" # liquidx contract on the EOS mainnet
name = "test1" # CHAIN_NAME - contract on the EOS mainnet that registered the new
˓→chain
mapping = "dappservices:dappservicex,heliosselene:heliosselene"
# [sidechains.ANOTHER_CHAIN_NAME]
# ...
Once this has been configured, the environment variables for the DSP can be updated with:
You can also upgrade to the latest version of the DSP software by following the steps: here.
On the EOS mainnet, the EOS mainnet’s DSP account must be connected to the new chain’s DSP account. This is
done using the addaccount command on the liquidx.dsp account.
• owner {name} - DSP account name on the EOS mainnet
• chain_account {name} - DSP account name on the new chain
• chain_name {name} - account name of contract on the EOS mainnet that registered the chain
Cleos example:
˓→"uuddlrlrbass","chain_account":"uuddlrlrbass","chain_name":"mynewchainnn"},
˓→"authorization":[{"actor":"uuddlrlrbass","permission":"active"}]}]}'
On the new chain you must find the account that has deployed the dappservicex.cpp code. This can be found
by asking a BP, a member of the community, or by checking the chainentry table on the liquidx.dsp contract
and providing the scope of the chain_name used to register in the previous step.
This will return the chain_meta field:
The dappservices_contract value is the name of the contract that has deployed the dappservicex.cpp
code, dappservicex in this case.
Once you have that then on the new chain, submit an adddsp action on that account.
• owner {name} - DSP name on new chain
• dsp {name} - DSP name on mainnet
Cleos example:
˓→"uuddlrlrbass","dsp":"uuddlrlrbass"},"authorization":[{"actor":"uuddlrlrbass",
˓→"permission":"active"}]}]}'
With that you have 2 way mapped your DSP account name. On the EOS Mainnet, the DSP’s account has been linked
to the new chain’s network. And on the new network, the EOS Mainnet’s DSP account has been verified.
With that, the DSP is ready to offer services.
Next: Use Services
The following chains have the dappservicex contract deployed and mapped.
Guide:
• CoVax - CoVax, powered by the DAPP Network, is a community-driven project to fight against COVID-19
collectively, read more here
• WAX
• WAX Test
• Telos
• Telos Test
• BOS
as a note, the dsp_port, webhook_dapp_port, demux_webhook_port must be unique per chain
96 Chapter 3. Liquidx
LiquidApps
3.4.1 CoVax
[sidechains.liquidxcovax]
# dsp
dsp_port = 3116
dsp_account = ""
dsp_private_key = ""
# nodeos
nodeos_host = ""
nodeos_port = 8888
nodeos_secured = false
nodeos_chainid = "63788f6e75cdb4ec9d8bb64ce128fa08005326a8b91702d0d03e81ba80e14d27
˓→"
nodeos_websocket_port = 8887
nodeos_latest = true
webhook_dapp_port = 8113
# demux
demux_webhook_port = 3196
demux_socket_mode = "sub"
demux_bypass_database_head_block = false
demux_max_pending_messages = 500
# sidechain
name = "liquidxcovax"
mapping = "dappservices:dappservicex,EOS_MAINNET_DSP_ACCOUNT:COVAX_DSP_ACCOUNT"
3.4.2 WAX
[sidechains.liquidxxxwax]
# dsp
dsp_port = 3117
dsp_account = ""
dsp_private_key = ""
# nodeos
nodeos_host = ""
nodeos_port = 8888
nodeos_secured = false
nodeos_chainid = "1064487b3cd1a897ce03ae5b6a865651747e2e152090f99c1d19d44e01aea5a4
˓→"
nodeos_websocket_port = 8887
nodeos_latest = true
webhook_dapp_port = 8114
# demux
demux_webhook_port = 3197
demux_socket_mode = "sub"
demux_bypass_database_head_block = false
demux_max_pending_messages = 500
# sidechain
name = "liquidxxxwax"
mapping = "dappservices:dappservicex,EOS_MAINNET_DSP_ACCOUNT:WAX_DSP_ACCOUNT"
[sidechains.liquidxxtwax]
# dsp
dsp_port = 3118
dsp_account = ""
dsp_private_key = ""
# nodeos
nodeos_host = ""
nodeos_port = 8888
nodeos_secured = false
nodeos_chainid = "f16b1833c747c43682f4386fca9cbb327929334a762755ebec17f6f23c9b8a12
˓→"
nodeos_websocket_port = 8887
nodeos_latest = true
webhook_dapp_port = 8115
# demux
demux_webhook_port = 3198
demux_socket_mode = "sub"
demux_bypass_database_head_block = false
demux_max_pending_messages = 500
# sidechain
name = "liquidxxtwax"
mapping = "dappservices:dappservicex,EOS_MAINNET_DSP_ACCOUNT:WAX_TEST_DSP_ACCOUNT"
3.4.4 Telos
[sidechains.liquidxxtlos]
# dsp
dsp_port = 3119
dsp_account = ""
dsp_private_key = ""
# nodeos
nodeos_host = ""
nodeos_port = 8888
nodeos_secured = false
nodeos_chainid = "4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11
˓→"
nodeos_websocket_port = 8887
nodeos_latest = true
webhook_dapp_port = 8116
# demux
demux_webhook_port = 3199
demux_socket_mode = "sub"
demux_bypass_database_head_block = false
demux_max_pending_messages = 500
# sidechain
name = "liquidxxtlos"
mapping = "dappservices:dappservicex,EOS_MAINNET_DSP_ACCOUNT:TELOS_DSP_ACCOUNT"
[sidechains.liquidxttlos]
# dsp
dsp_port = 3120
(continues on next page)
98 Chapter 3. Liquidx
LiquidApps
3.4.6 BOS
[sidechains.liquidxxxbos]
# dsp
dsp_port = 3121
dsp_account = ""
dsp_private_key = ""
# nodeos
nodeos_host = ""
nodeos_port = 8888
nodeos_secured = false
nodeos_chainid = "d5a3d18fbb3c084e3b1f3fa98c21014b5f3db536cc15d08f9f6479517c6a3d86
˓→"
nodeos_websocket_port = 8887
nodeos_latest = true
webhook_dapp_port = 8118
# demux
demux_webhook_port = 3201
demux_socket_mode = "sub"
demux_bypass_database_head_block = false
demux_max_pending_messages = 500
# sidechain
name = "liquidxxxbos"
mapping = "dappservices:dappservicex,EOS_MAINNET_DSP_ACCOUNT:BOS_DSP_ACCOUNT"
The following steps will cover how to enable the DAPP Network on a new chain. After performing these steps DSPs
will be able to set themselves up on the new chain.
Guide:
There are two accounts that must be created to enable LiquidX. One mainnet account to represent the chain name, and
one sidechain account to handle the DAPP service logic.
EOS Mainnet Account:
• Create an account that will become the name for the chain. A good name should be chosen that easily represents
the new chain as it is used in many places. This account will register the chain with the liquidx.dsp contract
on the mainnet. This account does not have a contract set to it.
New Chain:
• dappservicex - this contract is used to add new DSPs and to create links between accounts. This account will
need to be known to DSPs and developers wishing to operate on the network.
After both accounts are created, the dappservicex.cpp contract must be set to the account created on the side
chain. This contract can be found in the Zeus-sdk repo, or by unboxing the liquidx box with the following com-
mands:
npm i -g @liquidapps/zeus-cmd
zeus unbox liquidx
cd liquidx
zeus compile
cd contracts/eos
Ensure that you add [email protected] to the active permission level of the account.
You must execute the setchain action on the liquidx.dsp account on the EOS mainnet with the mainnet account
created to represent the chain name. The syntax is as follows:
• chain_name {name} - name of EOS mainnet account deploying chain, e.g., mynewchainnn
• chain_meta {chain_metadata_t} - chain data
– is_public {bool} - whether the chain is public
– is_single_node {bool} - whether chain is a single node
– dappservices_contract {std::string} - account that dappservicex.cpp is deployed to, e.g., dappser-
vicex
– chain_id {std::string} - chain ID of sidechain
– type {std::string} - type of blockchain, e.g., EOSIO
– endpoints {std::vectorstd::string} - list of public endpoints for developers to use
– chain_json_uri {std::vectorstd::string} - publicly available json file that declares chain statistics
Example cleos command:
cleos -u https://nodes.get-scatter.com:443 push transaction '{"delay_sec":0,"max_cpu_
˓→usage_ms":0,"actions":[{"account":"liquidx.dsp","name":"setchain","data":{"chain_
˓→name":"mynewchainnn","chain_meta":{"is_public":true,"is_single_node":false,
˓→"endpoints":[],"p2p_seeds":[],"chain_json_uri":""}},"authorization":[{"actor":
100
˓→"mynewchainnn","permission":"active"}]}]}' Chapter 3. Liquidx
LiquidApps
After that, you must run the init action on the dappservicex contract.
• chain_name {name} - name of EOS mainnet account deploying chain, e.g., mynewchainnn
Example cleos command:
˓→"liquidjungle"},"authorization":[{"actor":"dappservicex","permission":"active"}]}]}'
And now you’re setup to begin configuring DSPs and then enabling users to use DAPP Network services. DSPs and
developers will need to know the chain_name used on the mainnet and the account the dappservicex.cpp
contract was set to on the new chain.
After that: Become a DSP
After that: Use Services
• search
Covax
CoVax, powered by the DAPP Network, is a community-driven project to fight against COVID-19 collectively. If you
would like to become a block producer or a DAPP Service Provider for the chain, please visit the Telegram and ask
for information on obtaining an account(s).
Telegram link: https://t.me/CoVaxApp
Read more in our blog article release: https://medium.com/@liquidapps/
take-up-arms-against-covid-19-with-covax-964af0ec2951
Block Explorer | courtesy of EOSUSA
4.1.1 Docs:
The CoVax chain utilizes the LiquidX technology to enable DAPP Network services to be provided on EOSIO based
chains. To read more on LiquidX, please see the LiquidX section. To learn more about setting up a DAPP Service
Provider, see the getting started section.
To obtain a DAPP Service Provider account on CoVax, reach out in the CoVax Telegram channel: https://t.me/
CoVaxApp.
Block Explorer | courtesy of EOSUSA
Guide:
• Update config.toml file update config.toml environment variable file with the CoVax chain sidechain section
103
LiquidApps
• Push DSP account mapping action on EOS mainnet run adddsp action on the dappservicex contract on
the CoVax chain to link the CoVax chain DSP account to your EOS mainnet DSP account
• Push DSP account mapping action on CoVax Chain run the addaccount action on the liquidx.dsp
contract on the EOS mainnet to link the EOS mainnet DSP account to the CoVax chain DSP account
The config.toml file is the environment variable file used for DAPP Service Providers.
[sidechains]
[sidechains.liquidxcovax]
# dsp
dsp_port = 3116 # dsp port to run new chain's services on, this is the port
˓→developers will push to, must be unique per new chain
mapping = "dappservices:dappservicex,MAINNET_DSP_ACCOUNT:COVAX_CHAIN_DSP_ACCOUNT"
On the EOS mainnet, the EOS mainnet’s DSP account must be connected to the new chain’s DSP account. This is
done using the addaccount command on the liquidx.dsp account.
• owner {name} - DSP account name on the EOS mainnet
• chain_account {name} - DSP account name on the new chain, liquidxcovax
• chain_name {name} - account name of contract on the EOS mainnet that registered the chain
Cleos example:
˓→"uuddlrlrbass","chain_account":"uuddlrlrbass","chain_name":"liquidxcovax"},
˓→"authorization":[{"actor":"uuddlrlrbass","permission":"active"}]}]}'
Once you have that then on the CoVax chain, submit an adddsp action on that account.
• owner {name} - DSP name on new chain
• dsp {name} - DSP name on mainnet
Cleos example:
˓→"uuddlrlrbass","dsp":"uuddlrlrbass"},"authorization":[{"actor":"uuddlrlrbass",
˓→"permission":"active"}]}]}'
To obtain a Block Producer account on CoVax, reach out in the CoVax Telegram channel: https://t.me/CoVaxApp.
Hyperion: https://covax.eosrio.io/v2/docs/index.html | courtesy of eosriobrazil
Block Explorer | courtesy of EOSUSA
Guide:
• Genesis JSON
• Peers
• API Endpoints
• Snapshots
• Scripts
{
"initial_timestamp": "2018-03-18T08:55:11.000",
"initial_key": "EOS6HyUZskuWbHzhZx4Vi8ZxcaW28hte5MVGhejFGJeDbd6iYYXBn",
"initial_configuration": {
"max_block_net_usage": 1048576,
"target_block_net_usage_pct": 1000,
"max_transaction_net_usage": 524288,
"base_per_transaction_net_usage": 12,
"net_usage_leeway": 500,
"context_free_discount_net_usage_num": 20,
"context_free_discount_net_usage_den": 100,
"max_block_cpu_usage": 100000,
"target_block_cpu_usage_pct": 500,
"max_transaction_cpu_usage": 50000,
"min_transaction_cpu_usage": 100,
"max_transaction_lifetime": 3600,
"deferred_trx_expiration_window": 600,
"max_transaction_delay": 3888000,
"max_inline_action_size": 4096,
"max_inline_action_depth": 4,
(continues on next page)
4.3.2 Peers:
eosnode-covax.liquidapps.io:9876
node1.eosdsp.com:9888
dsp1.dappsolutions.app:9875
covax.maltablock.org:9876
covax.eosrio.io:8132
covax.eosn.io:9876
• http://eosnode-covax.liquidapps.io
• https://covax.eosn.io
• https://covax.eosdsp.com
4.3.4 Snapshots:
4.3.5 Scripts:
• genesis_start.sh
• start.sh
• stop.sh
• hard_replay.sh
• clean.sh
The following are a list of scripts from the bios boot sequence tutorial located here. The PURBLIC_KEY_HERE and
PRIVATE_KEY_HERE fields must be updated in the genesis_start.sh, start.sh, and hard_replay.sh
scripts.
To start the chain from genesis, run the genesis_start.sh file, then if you need to stop the chain, run stop.sh,
if you need to start again, run start.sh. If you get a dirty flag, run hard_replay.sh.
If you need to wipe everything, run stop.sh, clean.sh, genesis_start.sh.
If you need to install eosio, see the eosio node section of the docs.
mkdir biosboot
touch genesis.json
nano genesis.json
mkdir genesis
(continues on next page)
genesis_start.sh
#!/bin/bash
DATADIR="./blockchain"
CURDIRNAME=${PWD##*/}
if [ ! -d $DATADIR ]; then
mkdir -p $DATADIR;
fi
nodeos \
--genesis-json $DATADIR"/../../../genesis.json" \
--signature-provider PURBLIC_KEY_HERE=KEY:PRIVATE_KEY_HERE \
--plugin eosio::producer_plugin \
--plugin eosio::producer_api_plugin \
--plugin eosio::chain_plugin \
--plugin eosio::chain_api_plugin \
--plugin eosio::http_plugin \
--plugin eosio::history_api_plugin \
--plugin eosio::history_plugin \
--data-dir $DATADIR"/data" \
--blocks-dir $DATADIR"/blocks" \
--config-dir $DATADIR"/config" \
--producer-name $CURDIRNAME \
--http-server-address 127.0.0.1:8888 \
--p2p-listen-endpoint 127.0.0.1:9876 \
--p2p-peer-address localhost:9877 \
--access-control-allow-origin=* \
--contracts-console \
--http-validate-host=false \
--verbose-http-errors \
--enable-stale-production \
--wasm-runtime=eos-vm \
--eos-vm-oc-enable \
--p2p-peer-address eosnode-covax.liquidapps.io:9876 \
--p2p-peer-address node1.eosdsp.com:9888 \
--p2p-peer-address dsp1.dappsolutions.app:9875 \
--p2p-peer-address covax.maltablock.org:9876 \
--p2p-peer-address covax.eosrio.io:8132 \
--p2p-peer-address covax.eosn.io:9876 \
>> $DATADIR"/nodeos.log" 2>&1 & \
echo $! > $DATADIR"/eosd.pid"
start.sh
#!/bin/bash
DATADIR="./blockchain"
CURDIRNAME=${PWD##*/}
if [ ! -d $DATADIR ]; then
mkdir -p $DATADIR;
fi
nodeos \
--signature-provider PURBLIC_KEY_HERE=KEY:PRIVATE_KEY_HERE \
--plugin eosio::producer_plugin \
--plugin eosio::producer_api_plugin \
--plugin eosio::chain_plugin \
--plugin eosio::chain_api_plugin \
--plugin eosio::http_plugin \
--plugin eosio::history_api_plugin \
--plugin eosio::history_plugin \
--data-dir $DATADIR"/data" \
--blocks-dir $DATADIR"/blocks" \
--config-dir $DATADIR"/config" \
--producer-name $CURDIRNAME \
--http-server-address 0.0.0.0:8888 \
--p2p-listen-endpoint 0.0.0.0:9876 \
--access-control-allow-origin=* \
--contracts-console \
--http-validate-host=false \
--verbose-http-errors \
--enable-stale-production \
--wasm-runtime=eos-vm \
--eos-vm-oc-enable \
--p2p-peer-address eosnode-covax.liquidapps.io:9876 \
--p2p-peer-address node1.eosdsp.com:9888 \
--p2p-peer-address dsp1.dappsolutions.app:9875 \
--p2p-peer-address covax.maltablock.org:9876 \
--p2p-peer-address covax.eosrio.io:8132 \
--p2p-peer-address covax.eosn.io:9876 \
>> $DATADIR"/nodeos.log" 2>&1 & \
echo $! > $DATADIR"/eosd.pid"
stop.sh
#!/bin/bash
DATADIR="./blockchain/"
if [ -f $DATADIR"/eosd.pid" ]; then
pid=`cat $DATADIR"/eosd.pid"`
echo $pid
kill $pid
rm -r $DATADIR"/eosd.pid"
echo -ne "Stoping Node"
while true; do
[ ! -d "/proc/$pid/fd" ] && break
echo -ne "."
sleep 1
(continues on next page)
hard_replay.sh
#!/bin/bash
DATADIR="./blockchain"
CURDIRNAME=${PWD##*/}
if [ ! -d $DATADIR ]; then
mkdir -p $DATADIR;
fi
nodeos \
--signature-provider PURBLIC_KEY_HERE=KEY:PRIVATE_KEY_HERE \
--plugin eosio::producer_plugin \
--plugin eosio::producer_api_plugin \
--plugin eosio::chain_plugin \
--plugin eosio::chain_api_plugin \
--plugin eosio::http_plugin \
--plugin eosio::history_api_plugin \
--plugin eosio::history_plugin \
--data-dir $DATADIR"/data" \
--blocks-dir $DATADIR"/blocks" \
--config-dir $DATADIR"/config" \
--producer-name $CURDIRNAME \
--http-server-address 127.0.0.1:8888 \
--p2p-listen-endpoint 127.0.0.1:9876 \
--p2p-peer-address localhost:9877 \
--access-control-allow-origin=* \
--contracts-console \
--http-validate-host=false \
--verbose-http-errors \
--enable-stale-production \
--wasm-runtime=eos-vm \
--eos-vm-oc-enable \
--hard-replay-blockchain \
--p2p-peer-address eosnode-covax.liquidapps.io:9876 \
--p2p-peer-address node1.eosdsp.com:9888 \
--p2p-peer-address dsp1.dappsolutions.app:9875 \
--p2p-peer-address covax.maltablock.org:9876 \
--p2p-peer-address covax.eosrio.io:8132 \
--p2p-peer-address covax.eosn.io:9876 \
>> $DATADIR"/nodeos.log" 2>&1 & \
echo $! > $DATADIR"/eosd.pid"
clean.sh
#!/bin/bash
rm -fr blockchain
ls -al
• search
Services
5.1.1 Overview
Authentication of offchain APIs and services using EOSIO permissions and contract
5.1.2 Stage
Alpha
5.1.3 Version
0.4
5.1.4 Contract
authfndspsvc
5.1.5 Box
auth-dapp-service
111
LiquidApps
authusage
5.1.7 Tests
• auth-client.spec.js
• authenticator.spec.js
5.2.1 Overview
5.2.2 Stage
WIP
5.2.3 Version
0.0
5.2.4 Contract
liquidbillin
5.2.5 Box
bill-dapp-service
sdummy2
5.2.7 Tests
• bill.spec.js
5.3.1 Overview
Scheduled Transactions
5.3.2 Stage
beta
5.3.3 Version
0.9
5.3.4 Contract
cronservices
5.3.5 Box
cron-dapp-service
schedule
5.3.7 Tests
• cronconsumer.spec.js
• Consumer Contract Example
5.4.1 Overview
5.4.2 Stage
WIP
5.4.3 Version
0.5
5.4.4 Contract
dnsservices1
5.4.5 Box
dns-dapp-service
dnsq
5.4.7 Tests
• dnsconsumer.spec.js
• Consumer Contract Example
5.5.1 Overview
5.5.2 Stage
WIP
5.5.3 Version
0.0
5.5.4 Contract
historyservc
5.5.5 Box
history-dapp-service
hststore
hsthold
hstserve
hstreg
5.5.7 Tests
• history.spec.js
5.6.1 Overview
5.6.2 Stage
Stable
5.6.3 Version
1.4
5.6.4 Contract
ipfsservice1
5.6.5 Box
ipfs-dapp-service
commit
cleanup
warmup
warmupcode
warmuprow
cleanuprow
5.6.7 Tests
• dappservices.spec.js
• ipfsconsumer.spec.js
• oldipfscons.spec.js
• Consumer Contract Example
5.7.1 Overview
5.7.2 Stage
WIP
5.7.3 Version
0.0
5.7.4 Contract
kmsservices1
5.7.5 Box
kms-dapp-service
sdummy3
5.7.7 Tests
• kmsconsumer.spec.js
5.8.1 Overview
Log Service
5.8.2 Stage
Beta
5.8.3 Version
0.9
5.8.4 Contract
logservices1
5.8.5 Box
log-dapp-service
logevent
logclear
5.8.7 Tests
• logconsumer.spec.js
• Consumer Contract Example
5.9.1 Overview
Web/IBC/XIBC/VCPU/SQL Services
5.9.2 Stage
Beta
5.9.3 Version
0.9
5.9.4 Contract
oracleservic
5.9.5 Box
oracle-dapp-service
geturi
orcclean
5.9.7 Tests
• oracleconsumer.spec.js
• Consumer Contract Example
5.10.1 Overview
5.10.2 Stage
Alpha
5.10.3 Version
0.9
5.10.4 Contract
readfndspsvc
5.10.5 Box
readfn-dapp-service
rfnuse
5.10.7 Tests
• readfnconsumer.spec.js
• Consumer Contract Example
5.11.1 Overview
5.11.2 Stage
Alpha
5.11.3 Version
0.5
5.11.4 Contract
signfndspsvc
5.11.5 Box
sign-dapp-service
signtrx
sgcleanup
5.11.7 Tests
• sign.spec.js
5.12.1 Overview
5.12.2 Stage
Alpha
5.12.3 Version
0.5
5.12.4 Contract
liquidstorag
5.12.5 Box
storage-dapp-service
sdummy
5.12.7 Tests
• storage.spec.js
• Consumer Contract Example
5.13.1 Overview
5.13.2 Stage
Beta
5.13.3 Version
0.9
5.13.4 Contract
accountless1
5.13.5 Box
vaccounts-dapp-service
vexec
5.13.7 Tests
• vaccountsconsumer.spec.js
• Consumer Contract Example
5.14.1 Overview
5.14.2 Stage
PoC
5.14.3 Version
0.1
5.14.4 Contract
vcpuservices
5.14.5 Box
vcpu-dapp-service
vrun
vrunclean
5.14.7 Tests
• vcpuconsumer.spec.js
• Consumer Contract Example
• search
DAPP Tokens
The DAPP token is a multi-purpose utility token that grants access to the DAPP Network. It is designed to power an
ecosystem of utilities, resources, and services specifically serving the needs of dApp developers building user-centric
dApps.
6.1.1 Videos
123
LiquidApps
Users wishing to purchase DAPP with EOS tokens can do so through the instant track. Simply send EOS to the Instant
Registration Track Vendor Smart Contract and you will receive your DAPP tokens at the end of the current cycle (see
“Claiming DAPP Tokens” for further information about the claiming process).
The Regular Registration Track provides flexibility in purchasing DAPP tokens. You can use EOS tokens for any
desired purchase amount. For amounts exceeding 15,000 Swiss Franc (CHF) you may also purchase with ETH, BTC
or Fiat.
In order to open up the opportunity to all potential purchasers the DAPP Generation Event includes a verified track for
buyers who wish to use their ETH, BTC, FIAT or EOS to purchase DAPP tokens.
If you wish to participate in the DAPP Generation Event through the Regular Registration Track, you must complete
a KYC (Know Your Customer) verification process, facilitated by Altcoinomy, a Swiss-based licensed KYC operator.
6.3.1 Automatic
The auto claim mechanism does not require participants to push an action themselves to claim the tokens. This is
handled by the website automatically at the end of each cycle.
6.3.2 Manual
The manual claim function is always available and participants can claim their DAPP Tokens immediately after the
cycle ends by sending an explicit action depending on the track they selected.
Instant Registration Track
Regular Registration Track
Login with the wallet of your choice and enter your account in the “payer” field (YOUR_ACCOUNT_HERE) and
hit “Push Transaction”.
The year-long DAPP token Generation Event began on February 26th, 2019 and will last until January 2020, for a total
of 333 days. These 333 days will be split into 444 18-hour cycles, with each cycle receiving an allocation of 1,127,127
tokens.
The DAPP tokens are distributed through two unique independent purchase tracks—the Instant Registration Track
and the Regular Registration Track. At the end of each cycle, each one of the two Registration Tracks distributes
563,063.0630 DAPP tokens amongst that cycle’s participants, proportional to the amount of EOS sent by each pur-
chaser in that cycle.
Blockchain technology has the potential to enable a more free and fair economy to emerge by introducing an un-
precedented level of transparency and accountability to markets. At LiquidApps, we are firm proponents of the free
market ethos. Maintaining the integrity of the DAPP Generation Event is of the utmost importance to us, and, as such,
LiquidApps hereby commits to abstaining from participation in the DAPP Token Generation Event.
More information may be found in our whitepaper
6.5 Air-HODL
A total amount of 100,000,000 DAPP will be allocated and divided between all the accounts that hold EOS at block
#36,568,000 (“Pioneer Holders”) and distributed via our unique Air-HODL mechanism.
You can view all snapshot information here.
The Air-HODLed DAPP tokens will be distributed on a block by block basis, matching up to a maximum of 3 million
EOS per account. The tokens will be continuously vested on a block to block basis over a period of 2 years, so
the complete withdrawal will only be possible at the end of this period. These 2 years began as soon as the DAPP
Generation Event was launched. Any Pioneer Holder choosing to withdraw the Air-HODLed tokens before the end
of those 2 years will only receive the vested portion (i.e. 50% of the distributed DAPP tokens will be vested after 1
year). The remainder of their unvested DAPP tokens will be distributed to Pioneer Holders who are still holding their
Air-HODL DAPP tokens.
HODLers are allowed to stake their vested Air-HODLed tokens immediately using our new staking mechanics. With-
drawing the tokens will transfer the vested tokens to their DAPP account, forfeiting the unvested portion to be redis-
tributed amongst remaining eligible participants.
You can get more information on the Air-HODL and view your balance at: https://liquidapps.io/air-hodl
• search
FAQs
The DAPP token is a multi-purpose utility token designed to power an ecosystem of utilities, resources, & services
specifically serving the needs of dApp developers building user-centric dApps.
DAPP will have an intial supply of 1 billion tokens. The DAPP Token Smart Contract generates new DAPP Tokens
on an ongoing basis, at an annual inflation rate of 1-5%.
50% of the DAPP tokens will be distributed in a year-long token sale, while 10% will be Air-Hodl’d to EOS holders.
The team will receive 20% of the DAPP tokens, of which 6.5% is unlocked and the rest continuously vested (on a
block-by-block basis) over a period of 2 years. Our partners and advisors will receive 10% of the DAPP tokens, with
the remaining 10% designated towards our grant and bounty programs.
127
LiquidApps
7.1.4 Why do you need to use DAPP Token and not just EOS?
While we considered this approach at the beginning of our building journey, we decided against it for a number of
reasons:
• We look forward to growing the network exponentially and will require ever more hardware to provide quick
handling of large amounts of data accessible through a high-availability API. It is fair to assume that this kind
of service would require significant resources to operate and market, thus it would not be optimal for a BP to
take on this as a “side-job” (using a “free market” model that allows adapting price to cost).
• The BPs have a special role as trusted entities in the EOS ecosystem. DSPs are more similar to a cloud service
in this respect, where they are less reputational and more technical. Anyone, including BPs, corporate entities,
and private individuals, can become a DSP.
• Adding the DAPP Network mechanism as an additional utility of the EOS token would not only require a
complete consensus between all BPs, but adoption by all API nodes as well. Lack of complete consensus to
adopt this model as an integral part of the EOS protocol would result in a hard fork. (Unlike a system contract
update, this change would require everyone’s approval, not only 15 out of 21).
• Since the DAPP Network’s mechanism does not require the active 21 BPs’ consensus, it doesn’t require every BP
to cache ALL the data. Sharding the data across different entities enables true horizontal scaling. By separating
the functions and reward mechanisms of BPs and DSPs, The DAPP Network creates an incentive structure that
makes it possible for vRAM to scale successfully.
• We foresee many potential utilities for vRAM. One of those is getting vRAM to serve as a shared memory
solution between EOS side-chains when using IBC (Inter-Blockchain Communication). This can be extended
to chains with a different native token than EOS, allowing DAPP token to be a token for utilizing cross-chain
resources.
• We believe The DAPP Network should be a separate, complementary ecosystem (economy) to EOS. While the
EOS Mainnet is where consensus is established, the DAPP Network is a secondary trustless layer. DAPP token,
as the access token to the DSPs, will potentially power massive scaling of dApps for the first time.
An 18 hour cycle causes the start and end time to be constantly changing, giving people in all time zones an equal
opportunity to participate.
An Air-HODL is an airdrop with a vesting period. EOS token holders on the snapshot block receive DAPP tokens on
a pro-rata basis every block, with the complete withdrawal of funds possible only after 2 years. Should they choose to
sell their DAPP tokens, these holders forfeit the right to any future airdrop, increasing the share of DAPP tokens for
the remaining holders.
The DAPP Network is not a fork nor a side-chain but a trustless service layer (with an EOSIO compatible interface
to the mainnet), provided by DSPs (DAPP Service providers). This layer potentially allows better utilization of the
existing resources (the RAM and CPU resources provided to you as an EOS token holder). It does not require a
change in the base protocol (hard fork) nor a change in the system contract. DSPs don’t have to be active BPs nor
trusted/elected entities and can price their own services.
• What is a DSP?
• Who can be a DSP?
• Are DSPs required to run a full node?
• How are DSPs incentivized?
DSPs are individuals or entities who provide external storage capacity, communication services, and/or utilities to
dApp developers building on the blockchain, playing a crucial role in the DAPP network.
DSPs can be BPs, private individuals, corporations, or even anonymous entities. The only requirement is that each
DSP must meet the minimum specifications for operating a full node on EOS.
While DSPs could use a third-party node, this would add latency to many services, including vRAM. In some cases,
this latency could be significant. LiquidApps does not recommend running a DSP without a full node.
DSPs receive 1-5% of token inflation proportional to the total amount of DAPP tokens staked to their service packages.
RAM is a memory device used to store smart contract data on EOS. However, its limited capacity makes it difficult
to build and scale dApps. vRAM provides dApp developers with an efficient and affordable alternative for their data
storage needs.
vRAM is a complement to RAM. It is an alternative storage solution for developers building EOS dApps that are
RAM-compatible, decentralized, and enables storing & retrieving of potentially unlimited amounts of data affordably
and efficiently. It allows dApp developers to cache all relevant data in RAM to distributed file storage systems (IPFS,
BitTorent, HODLONG) hosted by DAPP Service Providers (DSPs), utilizing RAM to store only the data currently in
use. vRAM transactions are still stored in chain history and so are replayable even if all DSPs go offline.
7.3.3 How can we be sure that data cached with DSPs is not tampered with?
DSPs cache files on IPFS, a decentralized file-storage system that uses a hash function to ensure the integrity of the
data. You can learn more about IPFS here: https://www.youtube.com/watch?time_continue=2&v=8CMxDNuuAiQ
Developers who wish to use the vRAM System do so by staking DAPP tokens to their chosen DSP for the amount
specified by the Service Package they’ve chosen based on their needs. By staking DAPP, they receive access to the
DSP services, vRAM included.
• search
Patch Notes
8.1 latest
8.1.1 docs
8.1.2 @liquidapps/zeus-cmd
• use 8887 instead of 8889 for state history port to match DSP docs
8.1.3 @liquidapps/dsp
8.1.4 docs
8.2 2.0.4719
• add new service responses and requests when #define USE_ADVANCED_IPFS is used
• add warmuprow and cleanuprow, these allow for more efficient loading and cleaning of vram shard information
131
LiquidApps
• add warmupcode, which allows for vram to be accessed from external contracts and third party DSPs
• warmupcode is used automatically when required when the code specified in a multi-index table is something
other than self
• add ability for a contract to use vaccounts from another contract when #define VACCOUNTS_SUBSCRIBER
is used
– xvinit argument is replaced in this case with a name (instead of a chainid)
– xvinit must be used to set the name of the contract providing vaccounts functionality
– contract using vaccounts_subscriber must be staked to a DSP, but does not have to be same DSP that the
vaccounts host contract is staked to -fixes
– fixed issue where vaccount push requests are not forwarded to a staked provider
8.2.3 @liquidapps/dsp
8.2.4 @liquidapps/zeus-cmd
• split mapping into builtin and local file stored in ~/.zeus/ storage directory
• boxes added to the mapping using zeus deploy box and zeus box add go to the local mapping file to persist
between zeus updates
• when unboxing a box found in both files, the local mapping is given priority, but a warning is displayed
• added zeus box remove command to remove boxes from the local mapping
• added RC file ignore flag –rc-ignore to bypass it | thank you prcolaco
Example zeusrc.json:
{
"verbose": true,
"type": "local",
"update-mapping": true,
(continues on next page)
• added utility/tool for deserializing xvexec data (vaccount action data) Example:
deserializeVactionPayload('dappaccoun.t', '6136465e000000002a00000000000000aca376f206b8
'https://mainnet.eos.dfuse.io') returns
{
"payload":{
"expiry":"1581659745",
"nonce":"42",
"chainid":"ACA376F206B8FC25A6ED44DBDC66547C36C6C33E3A119FFBEAEF943642F0E906",
"action":{
"account":"",
"action_name":"transfervacc",
"authorization":[
],
"action_data":
˓→"70AE375C19FEAA49E0D336557DF8AA49010000000000000004454F5300000000026869"
}
},
"deserializedAction":{
"payload":{
"vaccount":"dapjwaewayrb",
"to":"dapjkzepavdy",
"quantity":"0.0001 EOS",
"memo":"hi"
}
}
}
• add RC file to load regular zeus-cmd options from, on ~/.zeus/zeusrc.json by default, changeable with –rc-file
option | thank you prcolaco
• zeus create contract <MY_CONTRACT> now creates MY_CONTRACT.cpp instead of main.cpp,
update cmake to use MY_CONTRACT.cpp
• use v2.0.4 nodeos
• fixes
– fix portfolio app requesting new oracle entries twice on load
– fix portfolio app double adding eos token balances
– Read past end of buffer - The issue was that an additional parameter was added to IPFS warmup
to enable new functionality. This caused a conflict for pre-existing contracts attempting to warmup IPFS
data. The parameter was removed.
– fixed and refactored get-table utility to work with new dsp api (get_uri) and nodeos >= 2.0.0.
8.2.5 @liquidapps/dapp-client
8.2.6 docs
8.2.7 LiquidX
• Added public_upload_vaccount endpoint. This endpoint can be used directly from the frontend by vac-
counts. The vaccount signs the file to upload, sends it to the DSP, which verifies and stores the file. Optionally,
it does some additional quota checks defined by the consumer contract: It can define max file sizes, daily global
upload limits, and daily limits on a per vaccount level.
• Added a storageconsumer contract testing the vaccount uploads + limits checking.
• Refactored the upload_public endpoint to a common.js file as most functionality is now also required by
the new upload_public_vaccount endpoint.
• Added two quick-fix options external and box to the sync-builtin-boxes command, because it did
not work with the public zeus-sdk repo. External should be set to true when using the public repo. The default
args are chosen in a way that they shouldn’t change anything if invoked as usual.
• changed the uploads to use base64 encoding instead of hex (in both dapp-client and server) to save some band-
width. Fixed the bytelength quota calculation
• Disable vaccount archive upload
• Use base64 as encoding for archive as well to match other encodings.
• Support public archive upload in dapp-client lib
• fixes
8.3 2.0.4002
• add DSP console log in common.js if minimum stake threshold not met for account’s DAPP stake to DSP’s
service package
• add reconnect mechanism to demux nodeos websocket
• update eos 1.8.7 nodeos
• add keysize support to the ipfs index.js file
• add DSP_CONSUMER_PAYS logic to config.toml, if true throws error if DSP permission not setup
• add DEMUX_BYPASS_DATABASE_HEAD_BLOCK to config.toml, if true bypasses database last pro-
cessed block as head block and uses config.toml head block
• add LIQUIDX_CONTRACT to config.toml, points to EOS mainnet account that hosts the liquidx con-
tract
• add [sidechains] section to config.toml
• add liquidx ability to offer service to other eosio based chains while using the EOS mainnet for staking,
billing, and claim rewards
• fixes
– add custom permissions for xcallback in generic-dapp-service-node file
– fix cron reschedule on error, use nextTrySeconds time
– NODEOS_SECURED, DSP_CONSUMER_PAYS, DEMUX_BYPASS_DATABASE_HEAD_BLOCK, ac-
cepted as bool or string when passed from toml, toml passes bools as strings, if set as an env variable
manually, will accept as a bool
• add --type=local flag to zeus deploy box command: deploys boxes locally to ~/.zeus/boxes/
instead of IPFS or s3. Must use with the --update-mapping flag. Together both flags (zeus deploy
box --type=local --update-mapping) updates the mapping.json file with file://.. as the
pointer | thank you prcolaco
• made --type=local and --update-mapping flags default for zeus deploy box command
• only use invalidation of ipfs with zeus deploy box command when the --type is ipfs | thank you
prcolaco
• modified and fixed ipfs cleanup script to support oracle cleanups
• allow zeus compile <CONTRACT_NAME>, zeus now allows you to only compile a contract by its name if
you like, or you can run zeus compile to run all
• add kill-port npm dependency to eos-extensions box
• move ipfs-daemon dependency from boxes/groups/core/build-extensions/zeus-box.
json to boxes/groups/dapp-network/dapp-services/zeus-box.json as IPFS is only
needed with the dapp-services box
• add utils/ipfs-service/get-table.js - Reads all vRAM tables of a smart contract and stores them
with the naming syntax: ${contract_name}-${table_name}-table.json
• add utils/ipfs-service/get-ordered-keys.js - Prints ordered vRAM table keys in ascending
order account/table/scope. This can be used to iterate over the entire table client side
• allow zeus test <CONTRACT_NAME>, zeus now allows you to only compile/test a contract by its name if
you like, or you can run zeus test -c to compile/test all
• add zeus vaccounts push-action test1v regaccount '{"vaccount":"vaccount1"}'
• add ability to import/export LiquidAccount keys
• implement storage dapp-client into storage service test storage-dapp-service/test/storage.
spec.js
• build dapp-client from source instead of installing by adding step to start-localenv
• use base58 instead of default base32 for LiquidStorage’s ipfs.files.add to match ipfs service
• add zeus test -c alias to compile all contracts, zeus test now does not compile by default
• Implementing reset, load, and save functionality for multi-index tables
– save: add zeus backup-table command which calls zeus/boxes/groups/
services/ipfs-dapp-service/utils/ipfs-service/backup.js to backup a
dapp::multi_index table
– add manifest table to advanced_multi_index.hpp which provides the sharding details for a ta-
ble, includes params: checksum256 next_available_key, uint32_t shards, uint32_t
buckets_per_shard, and std::map<uint64_t,std::vector<char>> shardbuckets
– add backup table to advanced_multi_index.hpp which provides the manifest details, includes
params: uint64_t id, ipfsmultihash_t manifest_uri, time_point timestamp, and
string description
– add the following actions to the ipfsconsumer example contract:
* testbig - tests storing an entry with a checksum256 primary key and stores a uint64_t test
number
* checkbig - checks entry checksum256 primary key returns correct value of test number
* testmed - tests storing an entry with a uint128_t primary key and stores a uint64_t test
number
* checkmed - checks entry uint128_t primary key returns correct value value of test number
* testindex - tests storing an entry with a uint64_t primary key and stores a uint64_t test
number
* testfind - checks entry uint64_t primary key returns correct value value of test number
– add following tables to ipfsconsumer example contract: bigentry - uses a checksum256 primary key,
medentry - uses a uint128_t primary key
– add keysize as parameter for zeus get-table-row command, options: 64 (uint64_t),
128 (uint128_t), 256 (uint256_t) and hex (eosio::checksum256)
– added the following unit tests: dapp::multi_index checksum256 Get Available Key,
IPFS Save Manifest, IPFS Clear, IPFS Load Manifest, and IPFS cache cleaned
after write
• add vmanifest table, getRawTreeData and getTreeData functions, and warmuprow and
cleanuprow service responses to _ipfs_impl.hpp file
• added new service request types warmuprow,cleanuprow to the ipfs service
• utilize over-eager loading in dapp::multi_index via warmuprow to reduce vRam latency by attempting
to load all required data in a single action
• update coldtoken unit tests to reflect new decrease in latency
• moved nodeos.log to /logs folder
• tail last 1mb of nodeos.log folder to keep upon restarting zeus test
• flag ipfsentries as pending commit to prevent duplicate requests
– If a contract uses a shardbucket multiple times, it will only have unique commits
– If multiple actions in the same block (or prior to the xcommit) need to lookup the same shardbucket,
there will be a single unique commit, and no additional warmups required
– If a contract uses a delayed commit, this delayed commit won’t be overwritten by an immediate commit
• update eosio.cdt to default to 1.6.3 if not installed
• add zeus box create and zeus box add commands
• add --sidechains ['{sidechain_provider:"dspnameeeeee",
service_contract:"ipfservice2",nodeos_endpoint:"https://api.jungle.
alohaeos.com:443",active_key:""}','{ ... another sidechain object }'] option
to zeus register dapp-service-provider-package" to regprovider with sidechains
• add zeus compile --sidechain=mychainnamee flag to compile a side chain name when using liq-
uidx
• use gateway port (3115) instead of service port (e.g. 13112 oracles) when running local zeus tests
• add liquidjungle box with /models/liquid-mappings for DSP files, service files, and the
dappservices:dappservicex mapping as well as /models/eosio-chains liquidjungle.
json chain config file
• add dappservicex (DAPP service contract for new chain) and liquidx (DAPP service contract for EOS
mainnet)
• rename all instances of local-sidechains to eosio-chains
• update eos to default to 1.8.7 if not installed
• fixes
– update example frontend to eosjs2 and latest scatter
– update cleanup script to work with new dsp logic
– add CONTRACT_END syntax to example contract
– fix cardgame unit test
• add keysize as argument for get vram row command, options: 64 (uint64_t), 128 (uint128_t),
256 (uint256_t) and hex (eosio::checksum256)
• add support for vconfig file, warmuprow and cleanuprow actions in node logic to support faster data
warmups
• fixes
– add fix text encode/decode in vaccounts service
8.3.5 docs
• removed read-mode = head from default config.ini setup for eosio node
• clarified wasm-runtime = wabt must be used over wasm-runtime = wavm due to bugs in wavm
• add zeus compile <CONTRACT_NAME> syntax to zeus-getting-started
• update path for cleanup.js script for DSPs
• add cleanup oracle info to Cleanup IPFS and Oracle Entries
• fixed little mistakes in vram-getting-started
• add usagex for LiquidX and other off chain service billing LiquidStorage, LiquidLens, LiquidAuth
• contract pays for CPU/NET/RAM associated with xactions xwarmup, xsignal, xcommit, xdcommit,
xvexec, etc
• fixes
– add DAPP token assertion to regpkg command to ensure DAPP symbol and 4 decimals of precision used
8.4 2.0.3107
8.4.4 docs
• add usagex for LiquidX and other off chain service billing LiquidStorage, LiquidLens, LiquidAuth
8.5 2.0.2812
• add vcpu-dapp-service
• add chess game zeus unbox chess
• enable large LiquidAccount payload sizes
• add unit test for oracle POST request
• add --phase command to specify dapp services file dapp-services-eos.js, install npm files npm, or
compile eos files eos
• fixes
– change instantiateBuffer to instantiateSync for vcpu vrun.js
– fix debian install for eosio.cdt due to syntax change in download link
8.5.4 docs
8.6 2.0.2527
• updated to eosjs 20
• added eosjs1 compatibility wrapper
• enable migration to non-local eos chains
• LiquidAccounts - add nonce, chain_id, and expiry to transactions params
• fixes
– Oracles - K out of N DSP results support. multi-dsp support fixes - adjust results size | code
– Scheduler - added callback retries and better contract verification of timers. easier rescheduling of timers
from callback (by returning ‘true’ in the function)
– LiquidAccounts - fixed potential replay attack. added expiry, nonce and chainid verification in contract.
Requires xvinit action to set chain_id for contract | code
8.6.4 docs
• Added IPFS info - bootstrap from existing node, swarm / bootstrap peers
• Added PostgressSQL Database info
• Updated EOS v1.8.4