Repository: LiskHQ/lisk-js
Branch: master
Commit: ecf1114006b4
Files: 203
Total size: 781.4 KB
Directory structure:
gitextract_nwrllr62/
├── .editorconfig
├── .gitignore
├── .lintstagedrc.json
├── .nvmrc
├── Jenkinsfile
├── Jenkinsfile.nightly
├── LICENSE
├── docs/
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE.md
│ └── PULL_REQUEST_TEMPLATE.md
├── lerna.json
├── package.json
├── packages/
│ ├── lisk-api-client/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── api_client.ts
│ │ │ ├── api_method.ts
│ │ │ ├── api_resource.ts
│ │ │ ├── api_types.ts
│ │ │ ├── constants.ts
│ │ │ ├── errors.ts
│ │ │ ├── index.ts
│ │ │ ├── resources/
│ │ │ │ ├── accounts.ts
│ │ │ │ ├── blocks.ts
│ │ │ │ ├── dapps.ts
│ │ │ │ ├── delegates.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── node.ts
│ │ │ │ ├── peers.ts
│ │ │ │ ├── signatures.ts
│ │ │ │ ├── transactions.ts
│ │ │ │ ├── voters.ts
│ │ │ │ └── votes.ts
│ │ │ └── utils.ts
│ │ └── test/
│ │ ├── _global_hooks.ts
│ │ ├── _setup.ts
│ │ ├── api_client.ts
│ │ ├── api_method.ts
│ │ ├── api_resource.ts
│ │ ├── constants.ts
│ │ ├── errors.ts
│ │ ├── index.ts
│ │ ├── mocha.opts
│ │ ├── resources/
│ │ │ ├── accounts.ts
│ │ │ ├── blocks.ts
│ │ │ ├── dapps.ts
│ │ │ ├── delegates.ts
│ │ │ ├── node.ts
│ │ │ ├── peers.ts
│ │ │ ├── signatures.ts
│ │ │ ├── transactions.ts
│ │ │ ├── voters.ts
│ │ │ └── votes.ts
│ │ └── utils.ts
│ ├── lisk-client/
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── prestart.sh
│ │ │ └── start.sh
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── test/
│ │ ├── _setup.ts
│ │ └── index.ts
│ ├── lisk-constants/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── test/
│ │ ├── _setup.ts
│ │ └── index.ts
│ ├── lisk-cryptography/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── benchmark/
│ │ │ └── nacl.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── buffer.ts
│ │ │ ├── constants.ts
│ │ │ ├── convert.ts
│ │ │ ├── encrypt.ts
│ │ │ ├── hash.ts
│ │ │ ├── index.ts
│ │ │ ├── keys.ts
│ │ │ ├── nacl/
│ │ │ │ ├── fast.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── nacl_types.ts
│ │ │ │ └── slow.ts
│ │ │ └── sign.ts
│ │ ├── test/
│ │ │ ├── _global_hooks.ts
│ │ │ ├── _setup.ts
│ │ │ ├── buffer.ts
│ │ │ ├── convert.ts
│ │ │ ├── encrypt.ts
│ │ │ ├── hash.ts
│ │ │ ├── helpers/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── keys.ts
│ │ │ ├── mocha.opts
│ │ │ ├── nacl/
│ │ │ │ ├── index.ts
│ │ │ │ └── nacl.ts
│ │ │ ├── sign.ts
│ │ │ └── tsconfig.json
│ │ └── types/
│ │ ├── browserify-bignum/
│ │ │ └── index.d.ts
│ │ ├── buffer-reverse/
│ │ │ └── index.d.ts
│ │ ├── sodium-native/
│ │ │ └── index.d.ts
│ │ └── varuint-bitcoin/
│ │ └── index.d.ts
│ ├── lisk-elements/
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── prestart.sh
│ │ │ └── start.sh
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── test/
│ │ ├── _setup.ts
│ │ └── index.ts
│ ├── lisk-passphrase/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── validation.ts
│ │ └── test/
│ │ ├── _setup.ts
│ │ ├── index.ts
│ │ └── validation.ts
│ └── lisk-transactions/
│ ├── LICENSE
│ ├── README.md
│ ├── fixtures/
│ │ ├── invalid_transactions.json
│ │ └── transactions.json
│ ├── package.json
│ ├── src/
│ │ ├── 0_transfer.ts
│ │ ├── 1_register_second_passphrase.ts
│ │ ├── 2_register_delegate.ts
│ │ ├── 3_cast_votes.ts
│ │ ├── 4_register_multisignature_account.ts
│ │ ├── 5_create_dapp.ts
│ │ ├── constants.ts
│ │ ├── create_signature_object.ts
│ │ ├── index.ts
│ │ ├── transaction_types.ts
│ │ └── utils/
│ │ ├── format.ts
│ │ ├── get_address_and_public_key_from_recipient_data.ts
│ │ ├── get_transaction_bytes.ts
│ │ ├── get_transaction_hash.ts
│ │ ├── get_transaction_id.ts
│ │ ├── index.ts
│ │ ├── prepare_transaction.ts
│ │ ├── sign_and_verify.ts
│ │ ├── sign_raw_transaction.ts
│ │ ├── time.ts
│ │ └── validation/
│ │ ├── index.ts
│ │ ├── schema.ts
│ │ ├── validate_transaction.ts
│ │ ├── validation.ts
│ │ └── validator.ts
│ ├── test/
│ │ ├── 0_transfer.ts
│ │ ├── 1_register_second_passphrase.ts
│ │ ├── 2_register_delegate.ts
│ │ ├── 3_cast_votes.ts
│ │ ├── 4_register_multisignature_account.ts
│ │ ├── 5_create_dapp.ts
│ │ ├── _global_hooks.ts
│ │ ├── _setup.ts
│ │ ├── constants.ts
│ │ ├── create_signature_object.ts
│ │ ├── index.ts
│ │ ├── mocha.opts
│ │ ├── tsconfig.json
│ │ └── utils/
│ │ ├── format.ts
│ │ ├── get_transaction_bytes.ts
│ │ ├── get_transaction_hash.ts
│ │ ├── get_transaction_id.ts
│ │ ├── index.ts
│ │ ├── prepare_transaction.ts
│ │ ├── sign_and_verify.ts
│ │ ├── sign_raw_transaction.ts
│ │ ├── time.ts
│ │ └── validation/
│ │ ├── validate_transaction.ts
│ │ ├── validation.ts
│ │ └── validator.ts
│ └── types/
│ ├── ajv-merge-patch/
│ │ └── index.d.ts
│ └── browserify-bignum/
│ └── index.d.ts
├── scripts/
│ └── init.sh
├── templates/
│ ├── .npmignore.tmpl
│ ├── .npmrc.tmpl
│ ├── .nycrc-ts.tmpl
│ ├── .prettierignore.tmpl
│ ├── .prettierrc.json.tmpl
│ ├── browsertest.tmpl/
│ │ ├── .eslintrc.json
│ │ ├── browsertest.html
│ │ ├── browsertest.min.html
│ │ ├── run_tests.js
│ │ └── setup.js
│ ├── cypress.json.tmpl
│ ├── cypress.tmpl/
│ │ └── integration/
│ │ └── index.js
│ ├── mocha.opts.ts.tmpl
│ ├── scripts.tmpl/
│ │ └── clean.sh
│ ├── tsconfig-test.json.tmpl
│ ├── tsconfig.browsertest.json.tmpl
│ ├── tsconfig.json.tmpl
│ ├── tslint-test.json.tmpl
│ └── tslint.json.tmpl
├── tsconfig.json
├── tslint.json
├── tslint.test.json
└── types/
├── chai/
│ └── index.d.ts
├── globals/
│ └── index.d.ts
└── json/
└── index.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
================================================
FILE: .gitignore
================================================
# General
.DS_Store
*.swp
*.orig
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
test/.coverage-unit
# nyc test coverage
.nyc_output
# cypress media
templates/cypress.tmpl/screenshots/
templates/cypress.tmpl/videos/
templates/cypress.tmpl/plugins/
templates/cypress.tmpl/support/
cypress/screenshots
cypress/videos
cypress/plugins
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# IDE directories
.idea
tmp
.vscode
# Distribution folders
dist-node/
dist-browser/
browsertest.build/
browsertest/package.json
browsertest/browsertest.js
browsertest/browsertest.min.js
browsertest/src
browsertest/test
# Unsupported lock files
yarn.lock
================================================
FILE: .lintstagedrc.json
================================================
{
"*.{ts,js}": ["prettier --write", "git add"]
}
================================================
FILE: .nvmrc
================================================
8.12.0
================================================
FILE: Jenkinsfile
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
@Library('lisk-jenkins') _
pipeline {
agent { node { label 'lisk-elements' } }
stages {
stage('Cancel previous running PR') {
steps {
script{
if (env.CHANGE_ID) {
// This is a Pull Request
cancelPreviousBuild()
}
}
}
}
stage('Install dependencies') {
steps {
script {
cache_file = restoreCache("package.json")
}
nvm(getNodejsVersion()) {
sh 'npm install --verbose'
}
script {
saveCache(cache_file, './node_modules', 10)
sh '''
if [ ! -f "/home/lisk/.cache/Cypress/$(jq -r .devDependencies.cypress ./packages/lisk-constants/package.json)/Cypress/Cypress" ]; then
./packages/lisk-constants/node_modules/.bin/cypress install --force
fi
'''
}
}
}
stage('Build') {
steps {
nvm(getNodejsVersion()) {
sh 'npm run build'
}
}
}
stage('Run lint') {
steps {
ansiColor('xterm') {
nvm(getNodejsVersion()) {
sh 'npm run lint'
}
}
}
}
stage('Run tests') {
steps {
ansiColor('xterm') {
nvm(getNodejsVersion()) {
sh 'npm run test'
}
}
}
}
stage('Run node tests') {
steps {
ansiColor('xterm') {
nvm(getNodejsVersion()) {
sh 'npm run test:node'
}
}
}
}
stage('Run browser tests') {
steps {
nvm(getNodejsVersion()) {
sh '''
npm run build:browsertest
npm run test:browser
'''
}
}
}
}
post {
success {
script {
build_info = getBuildInfo()
liskSlackSend('good', "Recovery: build ${build_info} was successful.")
}
deleteDir()
githubNotify context: 'continuous-integration/jenkins/lisk-elements', description: 'The build passed.', status: 'SUCCESS'
}
failure {
script {
build_info = getBuildInfo()
liskSlackSend('danger', "Build ${build_info} failed (<${env.BUILD_URL}/console|console>, <${env.BUILD_URL}/changes|changes>)\n")
}
archiveArtifacts allowEmptyArchive: true, artifacts: 'cypress/screenshots/'
githubNotify context: 'continuous-integration/jenkins/lisk-elements', description: 'The build failed.', status: 'FAILURE'
}
aborted {
githubNotify context: 'continuous-integration/jenkins/lisk-elements', description: 'The build was aborted.', status: 'ERROR'
}
}
}
================================================
FILE: Jenkinsfile.nightly
================================================
pipeline {
agent { node { label 'lisk-elements' } }
stages {
stage('Cache dependencies') {
steps {
nvm(getNodejsVersion()) {
sh 'npm install --verbose'
}
script {
sh '''
BRANCH=${CHANGE_TARGET:-${BRANCH_NAME:-development}}
if [ ! -d ~/cache/$BRANCH ]; then
mkdir ~/cache/$BRANCH
fi
rsync -axl --delete ./node_modules ~/cache/$BRANCH/
'''
}
}
}
}
post {
success {
deleteDir()
}
}
}
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: docs/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [info@lisk.io](mailto:info@lisk.io). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct/
[homepage]: https://www.contributor-covenant.org
================================================
FILE: docs/CONTRIBUTING.md
================================================
# Contributing to Lisk Elements
First off, thanks for taking the time to contribute! :raised_hands:
The following is a set of guidelines for contributing to Lisk Elements, which are hosted in the [LiskHQ Organization](https://github.com/LiskHQ) on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
#### Table Of Contents
1. [Code of Conduct](#code-of-conduct)
1. [Help! I don't want to read this whole thing, I just have one question. :mag_right:](#help!-i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
1. [How Can I Contribute?](#how-can-i-contribute)
1. [Reporting Bugs](#reporting-bugs)
1. [Suggesting Enhancements](#suggesting-enhancements)
1. [Pull Requests](#pull-requests)
1. [Styleguides](#styleguides)
1. [Git Commit Messages](#git-commit-messages)
1. [JavaScript Styleguide](#javascript-styleguide)
## Code of Conduct
This project and everyone participating in it is governed by the [Lisk Elements Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [info@lisk.io](mailto:info@lisk.io).
## Project License
Every repository within LiskHQ comes with a LICENSE file. Please read it carefully before commiting your code to one of the repositories.
## Help! I don't want to read this whole thing, I just have a question. :mag_right:
Lisk is an open-source decentralized project, there are many ways and platforms to get help. These are some of them:
* [Discuss and Ask on Reddit](https://www.reddit.com/r/Lisk/)
* [Lisk FAQ](https://docs.lisk.io/docs/faq)
If you prefer to chat with LiskHQ and other developers directly:
* [Join the LiskHQ Gitter](https://gitter.im/LiskHQ/lisk)
* Even though Gitter is a chat service, sometimes it takes several hours for community members to respond — please be patient!
## How Can I Contribute?
LiskHQ uses GitHub as its sole source of truth. Everything happens here. Lightcurve employees who contribute to Lisk are expected to do so in the same way as everyone else. In other words, this document applies equally to all contributors.
### `master` is unsafe for production use
We will do our best to keep `master` in good shape, with tests passing at all times. But in order to move fast, we will make API changes that your application might not be compatible with. We will do our best to communicate these changes and always version appropriately so you can lock into a specific, stable version.
### Pull Requests
Broadly speaking, we conform to the git flow branching model. For a description of this model, see [this introduction](https://datasift.github.io/gitflow/IntroducingGitFlow.html).
In case you've never submitted a pull request (PR) via GitHub before, please read [this short tutorial](https://help.github.com/articles/creating-a-pull-request). If you've submitted a PR before, there should be nothing surprising about our procedures for Lisk.
*Before* submitting a pull request, please make sure the following is done:
1. Fork the repo.
1. If you are creating a pull request that addresses a specific issue, take a look at the projects that issue is a part of (in the right-hand sidebar). Most issues will be a part of a project for a specific version, such as "Version 1.0.0". If this is the case, create your branch from the relevant version branch, e.g. `1.0.0`, and submit your pull request against that branch as a base. Otherwise, create your branch from master.
1. Add tests to the code you have contributed! All new code must come with complete test coverage. End all files with a newline. In general, your code should conform to the rules listed in the .editorconfig file. There are plugins for most editors/IDEs to do this for you automatically. Update the README for the changes that adhere to your new code.
1. Ensure the test and linting suite passes (`npm run prepush` runs both). Follow the JavaScript styleguide from Airbnb with the lisk extension.
1. Submit a pull request via GitHub. Include issue numbers in the PR title, at the end with: Description - Closes #IssueNumber. Also mention the #IssueNumber in the Comment, to easier browse to the issue.
1. Check that Jenkins CI tests pass (pull request turns green). First time contributors will need to wait for a trusted team member to start Jenkins CI on a Pull Request.
### Reporting Bugs
This section guides you through submitting a bug report for Lisk Elements. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE.md), the information it asks for helps us resolve issues faster.
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
#### Before Submitting A Bug Report
* **Check the [FAQs](https://docs.lisk.io/docs/faq)** for a list of common questions and problems.
* **Determine [which repository the problem should be reported in](https://github.com/LiskHQ)**.
* **Perform a [cursory search](https://github.com/search?utf8=%E2%9C%93&q=+is%3Aissue+org%3ALiskHQ&type=)** to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.
#### How Do I Submit A (Good) Bug Report?
Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](https://github.com/LiskHQ) your bug is related to, create an issue on that repository and provide the following information by filling in [the template](ISSUE_TEMPLATE.md).
Explain the problem and include additional details to help maintainers reproduce the problem:
* **Use a clear and descriptive title** for the issue to identify the problem.
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Lisk Elements, e.g. with Node.js or in the Browser (which one? which version?), or how you started Lisk Elements otherwise. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you have used an API model provide the configuration you have chosen and the functions you have executed. **Make sure to erase sensitive information from the configuration or details you are passing - NEVER SHARE YOUR SECRET PASSPHRASES OR PRIVATE KEYS**.
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
* **Explain which behavior you expected to see instead and why.**
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. You can use [this tool](http://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
Provide more context by answering these questions:
* **Did the problem start happening recently** (e.g. after updating to a new version of Lisk Elements, Lisk or any other repository) or was this always a problem?
* If the problem started happening recently, **can you reproduce the problem in an older version of Lisk Elements?** What's the most recent version in which the problem doesn't happen? You can download older versions of Lisk Elements from [the releases page](https://github.com/LiskHQ/lisk-elements/releases).
* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.
### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for Lisk Elements, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.
When you are creating an enhancement suggestion, please include as many details as possible. Fill in [the template](ISSUE_TEMPLATE.md), including the steps that you imagine you would take if the feature you're requesting existed.
#### How Do I Submit A (Good) Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](https://github.com/LiskHQ) your enhancement suggestion is related to, create an issue on that repository and provide the following information:
* **Use a clear and descriptive title** for the issue to identify the suggestion.
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Describe the current behavior** and **explain which behavior you expected to see instead** and why.
* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of Lisk Elements which the suggestion is related to. You can use [this tool](http://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
* **Explain why this enhancement would be useful** to most Lisk and Lisk Elements users.
* **Specify which version of Lisk and Lisk Elements you're using.**
* **Specify the name and version of the OS you're using.**
## Styleguides
### Git Commit Messages
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally after the first line
* Consider starting the commit message with an applicable emoji:
* :seedling: `:seedling:` when adding a new feature
* :bug: `:bug:` when fixing a bug
* :books: `:books:` when adding or updating documentation
* :nail_care: `:nail_care:` when making changes to code style (e.g. lint settings)
* :recycle: `:recycle:` when refactoring code
* :fire: `:fire:` when removing code or files (including dependencies)
* :racehorse: `:racehorse:` when improving performance
* :white_check_mark: `:white_check_mark:` when adding or updating tests
* :construction_worker: `:construction_worker:` when updating the build process
* :bowtie: `:bowtie:` when updating CI
* :house: `:house:` when performing chores
* :new: `:new:` when adding a new dependency
* :arrow_up: `:arrow_up:` when upgrading a dependency
* :arrow_down: `:arrow_down:` when downgrading a dependency
* :back: `:back:` when reverting changes
### JavaScript Styleguide
On Lisk Elements we are using [ESLint](https://eslint.org/).
Our JavaScript style expands [Airbnb's](https://github.com/airbnb/javascript) style. You can get more details here: https://github.com/LiskHQ/eslint-config-lisk-base
These contribution guidelines were inspired by and are based on Atom's contribution guidelines. They were modified for the purposes of this repository. https://github.com/atom/atom/blob/master/CONTRIBUTING.md - Copyright (c) 2011-2017 GitHub Inc. (MIT)
================================================
FILE: docs/ISSUE_TEMPLATE.md
================================================
### Expected behavior
### Actual behavior
### Steps to reproduce
### Which version(s) does this affect? (Environment, OS, etc...)
================================================
FILE: docs/PULL_REQUEST_TEMPLATE.md
================================================
### What was the problem?
### How did I fix it?
### How to test it?
### Review checklist
* The PR resolves #INSERT_ISSUE_NUMBER
* All new code is covered with unit tests
* All new code was formatted with Prettier
* Linting passes
* Tests pass
* Commit messages follow the [commit guidelines](CONTRIBUTING.md#git-commit-messages)
* Documentation has been added/updated
================================================
FILE: lerna.json
================================================
{
"lerna": "2.11.0",
"packages": ["packages/*"],
"version": "independent",
"stream": true
}
================================================
FILE: package.json
================================================
{
"name": "lisk-elements-monorepo",
"private": true,
"version": "1.0.0",
"description": "Reusable packages for use with the Lisk ecosystem",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=3 <=6"
},
"scripts": {
"bootstrap": "lerna bootstrap",
"clean": "lerna run clean",
"clean:node_modules": "lerna clean --yes",
"format": "npm run format:root && lerna run format",
"format:root": "prettier types/**/*.ts --write",
"lint": "npm run lint:root && lerna run lint",
"lint:fix": "npm run lint:root -- --fix && lerna run lint:fix",
"lint:root": "tslint -p tsconfig.json types/**/*.ts",
"test": "lerna run test",
"test:node": "lerna run test:node",
"test:browser": "lerna run test:browser",
"build": "lerna run build",
"build:browsertest": "lerna run build:browsertest",
"cover": "lerna run cover",
"init": "./scripts/init.sh",
"postinstall": "npm run bootstrap",
"precommit": "lint-staged && npm run lint",
"prepush": "npm run lint && npm test"
},
"devDependencies": {
"@types/node": "10.12.0",
"@types/sinon": "5.0.5",
"husky": "0.14.3",
"lerna": "3.4.1",
"lint-staged": "7.3.0",
"prettier": "1.14.2",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.1.1"
},
"dependencies": {}
}
================================================
FILE: packages/lisk-api-client/LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: packages/lisk-api-client/README.md
================================================
# @liskhq/lisk-api-client
@liskhq/lisk-api-client is containing an API client for the Lisk network
## Installation
```sh
$ npm install --save @liskhq/lisk-api-client
```
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-api-client/package.json
================================================
{
"name": "@liskhq/lisk-api-client",
"version": "2.0.0",
"description": "An API client for the Lisk network",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-api-client#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s liskAPIClient",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js ./browsertest.build/test/**/*.js -o ./browsertest.build/browsertest.js -s liskAPIClient",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{ts,js,json}\" \"{src,test}/**/*.{ts,js,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/{,/**/}/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11541 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11541) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11541 && cypress run --config baseUrl=http://localhost:11541 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@types/node": "10.10.1",
"@types/verror": "1.10.3",
"axios": "0.18.0",
"verror": "1.10.0"
},
"devDependencies": {
"@types/chai": "4.1.5",
"@types/chai-as-promised": "7.1.0",
"@types/expect": "1.20.3",
"@types/jquery": "3.3.9",
"@types/mocha": "5.2.5",
"@types/sinon": "5.0.5",
"@types/sinon-chai": "3.2.0",
"browserify": "16.2.2",
"chai": "4.1.2",
"chai-as-promised": "7.1.1",
"cypress": "3.1.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"sinon": "6.2.0",
"sinon-chai": "3.2.0",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-api-client/src/api_client.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as os from 'os';
import { HashMap, InitOptions } from './api_types';
import * as constants from './constants';
import { AccountsResource } from './resources/accounts';
import { BlocksResource } from './resources/blocks';
import { DappsResource } from './resources/dapps';
import { DelegatesResource } from './resources/delegates';
import { NodeResource } from './resources/node';
import { PeersResource } from './resources/peers';
import { SignaturesResource } from './resources/signatures';
import { TransactionsResource } from './resources/transactions';
import { VotersResource } from './resources/voters';
import { VotesResource } from './resources/votes';
const defaultOptions = {
bannedNodes: [],
randomizeNodes: true,
};
const commonHeaders: HashMap = {
Accept: 'application/json',
'Content-Type': 'application/json',
};
const getClientHeaders = (clientOptions: ClientOptions): HashMap => {
const { name = '????', version = '????', engine = '????' } = clientOptions;
const liskElementsInformation =
'LiskElements/1.0 (+https://github.com/LiskHQ/lisk-elements)';
const locale: string | undefined =
process.env.LC_ALL ||
process.env.LC_MESSAGES ||
process.env.LANG ||
process.env.LANGUAGE;
const systemInformation = `${os.platform()} ${os.release()}; ${os.arch()}${
locale ? `; ${locale}` : ''
}`;
return {
'User-Agent': `${name}/${version} (${engine}) ${liskElementsInformation} ${systemInformation}`,
};
};
export interface ClientOptions {
readonly engine?: string;
readonly name?: string;
readonly version?: string;
}
export class APIClient {
public static get constants(): typeof constants {
return constants;
}
public static createMainnetAPIClient(options?: InitOptions): APIClient {
return new APIClient(constants.MAINNET_NODES, {
nethash: constants.MAINNET_NETHASH,
...options,
});
}
public static createTestnetAPIClient(options?: InitOptions): APIClient {
return new APIClient(constants.TESTNET_NODES, {
nethash: constants.TESTNET_NETHASH,
...options,
});
}
public accounts: AccountsResource;
public bannedNodes!: ReadonlyArray;
public blocks: BlocksResource;
public currentNode!: string;
public dapps: DappsResource;
public delegates: DelegatesResource;
public headers!: HashMap;
public node: NodeResource;
public nodes!: ReadonlyArray;
public peers: PeersResource;
public randomizeNodes!: boolean;
public signatures: SignaturesResource;
public transactions: TransactionsResource;
public voters: VotersResource;
public votes: VotesResource;
public constructor(
nodes: ReadonlyArray,
providedOptions: InitOptions = {},
) {
this.initialize(nodes, providedOptions);
this.accounts = new AccountsResource(this);
this.blocks = new BlocksResource(this);
this.dapps = new DappsResource(this);
this.delegates = new DelegatesResource(this);
this.node = new NodeResource(this);
this.peers = new PeersResource(this);
this.signatures = new SignaturesResource(this);
this.transactions = new TransactionsResource(this);
this.voters = new VotersResource(this);
this.votes = new VotesResource(this);
}
public banActiveNode(): boolean {
return this.banNode(this.currentNode);
}
public banActiveNodeAndSelect(): boolean {
const banned = this.banActiveNode();
if (banned) {
this.currentNode = this.getNewNode();
}
return banned;
}
public banNode(node: string): boolean {
if (!this.isBanned(node)) {
this.bannedNodes = [...this.bannedNodes, node];
return true;
}
return false;
}
public getNewNode(): string {
const nodes = this.nodes.filter(
(node: string): boolean => !this.isBanned(node),
);
if (nodes.length === 0) {
throw new Error('Cannot get new node: all nodes have been banned.');
}
const randomIndex = Math.floor(Math.random() * nodes.length);
return nodes[randomIndex];
}
public hasAvailableNodes(): boolean {
return this.nodes.some((node: string): boolean => !this.isBanned(node));
}
public initialize(
nodes: ReadonlyArray,
providedOptions: InitOptions = {},
): void {
if (!Array.isArray(nodes) || nodes.length <= 0) {
throw new Error('APIClient requires nodes for initialization.');
}
if (typeof providedOptions !== 'object' || Array.isArray(providedOptions)) {
throw new Error(
'APIClient takes an optional object as the second parameter.',
);
}
const options: InitOptions = { ...defaultOptions, ...providedOptions };
this.headers = {
...commonHeaders,
...(options.nethash ? { nethash: options.nethash } : {}),
...(options.client ? getClientHeaders(options.client) : {}),
};
this.nodes = nodes;
this.bannedNodes = [...(options.bannedNodes || [])];
this.currentNode = options.node || this.getNewNode();
this.randomizeNodes = options.randomizeNodes !== false;
}
public isBanned(node: string): boolean {
return this.bannedNodes.includes(node);
}
}
================================================
FILE: packages/lisk-api-client/src/api_method.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { AxiosRequestConfig } from 'axios';
import {
APIHandler,
APIResponse,
HashMap,
RequestConfig,
Resource,
} from './api_types';
import { GET } from './constants';
import { solveURLParams, toQueryString } from './utils';
// Bind to resource class
export const apiMethod = (options: RequestConfig = {}): APIHandler =>
async function apiHandler(
this: Resource,
// tslint:disable-next-line readonly-array
...args: Array
): Promise {
const {
method = GET,
path = '',
urlParams = [],
validator,
defaultData = {},
retry = false,
} = options;
if (urlParams.length > 0 && args.length < urlParams.length) {
return Promise.reject(
new Error(
`This endpoint must be supplied with the following parameters: ${urlParams.toString()}`,
),
);
}
const data = {
...defaultData,
...(args.length > urlParams.length &&
typeof args[urlParams.length] === 'object'
? (args[urlParams.length] as object)
: {}),
};
if (validator) {
try {
validator(data);
} catch (err) {
return Promise.reject(err);
}
}
const resolvedURLObject = urlParams.reduce(
// tslint:disable-next-line no-inferred-empty-object-type
(accumulator: HashMap, param: string, i: number): HashMap => {
const value = args[i];
if (typeof value !== 'string' && typeof value !== 'number') {
throw new Error('Parameter must be a string or a number');
}
return {
...accumulator,
[param]: typeof value === 'number' ? value.toString() : value,
};
},
{},
);
const requestData: AxiosRequestConfig = {
headers: this.headers,
method,
url: solveURLParams(`${this.resourcePath}${path}`, resolvedURLObject),
};
if (Object.keys(data).length > 0) {
if (method === GET) {
requestData.url += `?${toQueryString(data)}`;
} else {
requestData.data = data;
}
}
return this.request(requestData, retry);
};
================================================
FILE: packages/lisk-api-client/src/api_resource.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import Axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { APIClient } from './api_client';
import { APIErrorResponse, APIResponse, HashMap } from './api_types';
import { APIError } from './errors';
const API_RECONNECT_MAX_RETRY_COUNT = 3;
const REQUEST_RETRY_TIMEOUT = 1000;
export class APIResource {
public apiClient: APIClient;
public path: string;
public constructor(apiClient: APIClient) {
this.apiClient = apiClient;
this.path = '';
}
public get headers(): HashMap {
return this.apiClient.headers;
}
public get resourcePath(): string {
return `${this.apiClient.currentNode}/api${this.path}`;
}
public async handleRetry(
error: Error,
req: AxiosRequestConfig,
retryCount: number,
): Promise {
if (this.apiClient.hasAvailableNodes()) {
return new Promise(resolve =>
setTimeout(resolve, REQUEST_RETRY_TIMEOUT),
).then(
async (): Promise => {
if (retryCount > API_RECONNECT_MAX_RETRY_COUNT) {
throw error;
}
if (this.apiClient.randomizeNodes) {
this.apiClient.banActiveNodeAndSelect();
}
return this.request(req, true, retryCount + 1);
},
);
}
return Promise.reject(error);
}
public async request(
req: AxiosRequestConfig,
retry: boolean,
retryCount: number = 1,
): Promise {
const request = Axios.request(req)
.then((res: AxiosResponse) => res.data)
.catch(
(error: AxiosError): void => {
if (error.response) {
const { status } = error.response;
if (error.response.data) {
const {
error: errorString,
errors,
message,
}: APIErrorResponse = error.response.data;
throw new APIError(
message || errorString || 'An unknown error has occurred.',
status,
errors,
);
}
throw new APIError('An unknown error has occurred.', status);
}
throw error;
},
);
if (retry) {
return request.catch(async (err: Error) =>
this.handleRetry(err, req, retryCount),
);
}
return request;
}
}
================================================
FILE: packages/lisk-api-client/src/api_types.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
/* tslint:disable no-mixed-interface */
export type APIHandler = (
// tslint:disable-next-line readonly-array
...args: Array
) => Promise;
export interface APIResponse {
readonly data: unknown;
readonly links: object;
readonly meta: object;
}
export interface APIErrorResponse {
readonly error?: string;
readonly errors?: ReadonlyArray;
readonly message?: string;
}
export interface APIErrorContents {
readonly code?: string;
readonly message?: string;
}
export interface HashMap {
readonly [key: string]: string;
}
export interface InitOptions {
readonly bannedNodes?: ReadonlyArray;
readonly client?: object;
readonly nethash?: string;
readonly node?: string;
readonly randomizeNodes?: boolean;
}
export interface RequestConfig {
readonly defaultData?: object;
readonly method?: string;
readonly path?: string;
readonly retry?: boolean;
readonly urlParams?: ReadonlyArray;
readonly validator?: (data: { readonly needed?: string }) => void;
}
export interface Resource {
readonly headers: HashMap;
readonly path: string;
readonly request: (data: object, retry: boolean) => Promise;
readonly resourcePath: string;
}
================================================
FILE: packages/lisk-api-client/src/constants.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export const GET = 'GET';
export const POST = 'POST';
export const PUT = 'PUT';
export const TESTNET_NETHASH =
'da3ed6a45429278bac2666961289ca17ad86595d33b31037615d4b8e8f158bba';
export const MAINNET_NETHASH =
'ed14889723f24ecc54871d058d98ce91ff2f973192075c0155ba2b7b70ad2511';
export const TESTNET_NODES: ReadonlyArray = [
'https://testnet.lisk.io:443',
];
export const MAINNET_NODES: ReadonlyArray = [
'https://node01.lisk.io:443',
'https://node02.lisk.io:443',
'https://node03.lisk.io:443',
'https://node04.lisk.io:443',
'https://node05.lisk.io:443',
'https://node06.lisk.io:443',
'https://node07.lisk.io:443',
'https://node08.lisk.io:443',
];
================================================
FILE: packages/lisk-api-client/src/errors.ts
================================================
import { VError } from 'verror';
const defaultErrorNo = 500;
export interface APIErrorData {
readonly code?: string;
readonly message?: string;
}
export class APIError extends VError {
public errno: number;
public errors?: ReadonlyArray;
public constructor(
message: string = '',
errno: number = defaultErrorNo,
errors?: ReadonlyArray,
) {
super(message);
this.name = 'APIError';
this.errno = errno;
this.errors = errors;
}
}
================================================
FILE: packages/lisk-api-client/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export * from './api_client';
================================================
FILE: packages/lisk-api-client/src/resources/accounts.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class AccountsResource extends APIResource {
public get: APIHandler;
public getMultisignatureGroups: APIHandler;
public getMultisignatureMemberships: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/accounts';
this.get = apiMethod({
method: GET,
}).bind(this);
this.getMultisignatureGroups = apiMethod({
method: GET,
path: '/{address}/multisignature_groups',
urlParams: ['address'],
}).bind(this);
this.getMultisignatureMemberships = apiMethod({
method: GET,
path: '/{address}/multisignature_memberships',
urlParams: ['address'],
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/blocks.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class BlocksResource extends APIResource {
public get: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/blocks';
this.get = apiMethod({
method: GET,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/dapps.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class DappsResource extends APIResource {
public get: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/dapps';
this.get = apiMethod({
method: GET,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/delegates.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class DelegatesResource extends APIResource {
public get: APIHandler;
public getForgers: APIHandler;
public getForgingStatistics: APIHandler;
public getStandby: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/delegates';
this.get = apiMethod({
defaultData: {
sort: 'rank:asc',
},
method: GET,
}).bind(this);
this.getStandby = apiMethod({
defaultData: {
offset: 101,
sort: 'rank:asc',
},
method: GET,
}).bind(this);
this.getForgers = apiMethod({
method: GET,
path: '/forgers',
}).bind(this);
this.getForgingStatistics = apiMethod({
method: GET,
path: '/{address}/forging_statistics',
urlParams: ['address'],
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export { default as AccountsResource } from './accounts';
export { default as BlocksResource } from './blocks';
export { default as DappsResource } from './dapps';
export { default as DelegatesResource } from './delegates';
export { default as NodeResource } from './node';
export { default as PeersResource } from './peers';
export { default as SignaturesResource } from './signatures';
export { default as TransactionsResource } from './transactions';
export { default as VotersResource } from './voters';
export { default as VotesResource } from './votes';
================================================
FILE: packages/lisk-api-client/src/resources/node.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET, PUT } from '../constants';
export class NodeResource extends APIResource {
public getConstants: APIHandler;
public getForgingStatus: APIHandler;
public getStatus: APIHandler;
public getTransactions: APIHandler;
public path: string;
public updateForgingStatus: APIHandler;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/node';
this.getConstants = apiMethod({
method: GET,
path: '/constants',
}).bind(this);
this.getStatus = apiMethod({
method: GET,
path: '/status',
}).bind(this);
this.getForgingStatus = apiMethod({
method: GET,
path: '/status/forging',
}).bind(this);
this.updateForgingStatus = apiMethod({
method: PUT,
path: '/status/forging',
}).bind(this);
this.getTransactions = apiMethod({
method: GET,
path: '/transactions/{state}',
urlParams: ['state'],
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/peers.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class PeersResource extends APIResource {
public get: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/peers';
this.get = apiMethod({
method: GET,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/signatures.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { POST } from '../constants';
export class SignaturesResource extends APIResource {
public broadcast: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/signatures';
this.broadcast = apiMethod({
method: POST,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/transactions.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET, POST } from '../constants';
export class TransactionsResource extends APIResource {
public broadcast: APIHandler;
public get: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/transactions';
this.get = apiMethod({
method: GET,
}).bind(this);
this.broadcast = apiMethod({
method: POST,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/voters.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class VotersResource extends APIResource {
public get: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/voters';
this.get = apiMethod({
method: GET,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/resources/votes.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../api_client';
import { apiMethod } from '../api_method';
import { APIResource } from '../api_resource';
import { APIHandler } from '../api_types';
import { GET } from '../constants';
export class VotesResource extends APIResource {
public get: APIHandler;
public path: string;
public constructor(apiClient: APIClient) {
super(apiClient);
this.path = '/votes';
this.get = apiMethod({
method: GET,
}).bind(this);
}
}
================================================
FILE: packages/lisk-api-client/src/utils.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { HashMap } from './api_types';
export const toQueryString = (obj: HashMap): string => {
const parts = Object.keys(obj).reduce(
(
accumulator: ReadonlyArray,
key: string,
): ReadonlyArray => [
...accumulator,
`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`,
],
[],
);
return parts.join('&');
};
const urlParamRegex = /{[^}]+}/;
export const solveURLParams = (url: string, params: HashMap = {}): string => {
if (Object.keys(params).length === 0) {
if (url.match(urlParamRegex) !== null) {
throw new Error('URL is not completely solved');
}
return url;
}
const solvedURL = Object.keys(params).reduce(
(accumulator: string, key: string): string =>
accumulator.replace(`{${key}}`, params[key]),
url,
);
if (solvedURL.match(urlParamRegex) !== null) {
throw new Error('URL is not completely solved');
}
return encodeURI(solvedURL);
};
================================================
FILE: packages/lisk-api-client/test/_global_hooks.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
afterEach(() => {
return sandbox.restore();
});
================================================
FILE: packages/lisk-api-client/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import 'chai/register-expect';
import sinonChai from 'sinon-chai';
import sinon from 'sinon';
process.env.NODE_ENV = 'test';
[sinonChai, chaiAsPromised].forEach(plugin => chai.use(plugin));
global.sandbox = sinon.createSandbox({
useFakeTimers: true,
});
================================================
FILE: packages/lisk-api-client/test/api_client.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import os from 'os';
import { APIClient } from '../src/api_client';
describe('APIClient module', () => {
const mainnetHash =
'ed14889723f24ecc54871d058d98ce91ff2f973192075c0155ba2b7b70ad2511';
const mainnetNodes: ReadonlyArray = [
'https://node01.lisk.io:443',
'https://node02.lisk.io:443',
'https://node03.lisk.io:443',
'https://node04.lisk.io:443',
'https://node05.lisk.io:443',
'https://node06.lisk.io:443',
'https://node07.lisk.io:443',
'https://node08.lisk.io:443',
];
const testnetHash =
'da3ed6a45429278bac2666961289ca17ad86595d33b31037615d4b8e8f158bba';
const testnetNodes: ReadonlyArray = ['https://testnet.lisk.io:443'];
const locale =
process.env.LC_ALL ||
process.env.LC_MESSAGES ||
process.env.LANG ||
process.env.LANGUAGE;
const platformInfo = `${os.platform()} ${os.release()}; ${os.arch()}${
locale ? `; ${locale}` : ''
}`;
const baseUserAgent = `LiskElements/1.0 (+https://github.com/LiskHQ/lisk-elements) ${platformInfo}`;
const customUserAgent = `LiskHub/5.0 (+https://github.com/LiskHQ/lisk-hub) ${baseUserAgent}`;
const defaultHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
};
const customHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
'User-Agent': customUserAgent,
nethash: testnetHash,
};
const localNode = 'http://localhost:7000';
const externalNode = 'https://googIe.com:8080';
const sslNode = 'https://external.lisk.io:443';
const externalTestnetNode = 'http://testnet.lisk.io';
const defaultNodes: ReadonlyArray = [
localNode,
externalNode,
sslNode,
];
const defaultSelectedNode = 'selected_node';
let apiClient: APIClient;
beforeEach(() => {
apiClient = new APIClient(defaultNodes);
return Promise.resolve();
});
describe('#constructor', () => {
let initializeStub: () => void;
beforeEach(() => {
initializeStub = sandbox.stub(APIClient.prototype, 'initialize');
return Promise.resolve();
});
it('should create a new instance of APIClient', () => {
return expect(apiClient)
.to.be.an('object')
.and.be.instanceof(APIClient);
});
it('should call initialize with the nodes and default options', () => {
apiClient = new APIClient(defaultNodes);
return expect(initializeStub).to.be.calledWithExactly(defaultNodes, {});
});
it('should call initialize with the nodes and provided options', () => {
const providedOptions = {
nethash:
'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
};
apiClient = new APIClient(defaultNodes, providedOptions);
return expect(initializeStub).to.be.calledWithExactly(
defaultNodes,
providedOptions,
);
});
});
describe('#createMainnetAPIClient', () => {
let client: APIClient;
beforeEach(() => {
client = APIClient.createMainnetAPIClient();
return Promise.resolve();
});
it('should return APIClient instance', () => {
return expect(client).to.be.instanceof(APIClient);
});
it('should contain mainnet nodes', () => {
return expect(client.nodes).to.eql(mainnetNodes);
});
it('should be set to mainnet hash', () => {
return expect(client.headers.nethash).to.equal(mainnetHash);
});
});
describe('#createTestnetAPIClient', () => {
let client: APIClient;
beforeEach(() => {
client = APIClient.createTestnetAPIClient();
return Promise.resolve();
});
it('should return APIClient instance', () => {
return expect(client).to.be.instanceof(APIClient);
});
it('should contain testnet nodes', () => {
return expect(client.nodes).to.eql(testnetNodes);
});
it('should be set to testnet hash', () => {
return expect(client.headers.nethash).to.equal(testnetHash);
});
});
describe('#constants', () => {
it('should expose API constants', () => {
return expect(APIClient.constants).to.be.an('object');
});
});
describe('#initialize', () => {
it('should throw an error if no arguments are passed to constructor', () => {
return expect(apiClient.initialize.bind(apiClient)).to.throw(
Error,
'APIClient requires nodes for initialization.',
);
});
it('should throw an error if first argument passed to constructor is not array', () => {
return expect(apiClient.initialize.bind(apiClient, 'non-array')).to.throw(
Error,
'APIClient requires nodes for initialization.',
);
});
it('should throw an error if first argument passed to constructor is empty array', () => {
return expect(apiClient.initialize.bind(apiClient, [])).to.throw(
Error,
'APIClient requires nodes for initialization.',
);
});
it('should throw an error if second argument passed to constructor is a string', () => {
return expect(
apiClient.initialize.bind(apiClient, defaultNodes, 'option string'),
).to.throw(
Error,
'APIClient takes an optional object as the second parameter.',
);
});
it('should throw an error if second argument passed to constructor is an array', () => {
return expect(
apiClient.initialize.bind(apiClient, defaultNodes, []),
).to.throw(
Error,
'APIClient takes an optional object as the second parameter.',
);
});
describe('headers', () => {
it('should set with passed nethash, with default options', () => {
return expect(apiClient)
.to.have.property('headers')
.and.eql(defaultHeaders);
});
it('should set custom headers with supplied options', () => {
apiClient = new APIClient(defaultNodes, {
nethash: testnetHash,
client: {
name: 'LiskHub',
version: '5.0',
engine: '+https://github.com/LiskHQ/lisk-hub',
},
});
return expect(apiClient)
.to.have.property('headers')
.and.eql(customHeaders);
});
it('should not set User-Agent header when client options were not given', () => {
apiClient = new APIClient(defaultNodes, {
nethash: testnetHash,
});
return expect(apiClient.headers).to.not.have.property('User-Agent');
});
});
describe('nodes', () => {
it('should have nodes supplied to constructor', () => {
return expect(apiClient)
.to.have.property('nodes')
.and.equal(defaultNodes);
});
});
describe('bannedNodes', () => {
it('should set empty array if no option is passed', () => {
return expect(apiClient)
.to.have.property('bannedNodes')
.be.eql([]);
});
it('should set bannedNodes when passed as an option', () => {
const bannedNodes = ['a', 'b'];
apiClient = new APIClient(defaultNodes, { bannedNodes });
return expect(apiClient)
.to.have.property('bannedNodes')
.be.eql(bannedNodes);
});
});
describe('currentNode', () => {
it('should set with random node with initialized setup if no node is specified by options', () => {
return expect(apiClient).to.have.property('currentNode').and.not.be
.empty;
});
it('should set with supplied node if node is specified by options', () => {
apiClient = new APIClient(defaultNodes, {
node: externalTestnetNode,
});
return expect(apiClient)
.to.have.property('currentNode')
.and.equal(externalTestnetNode);
});
});
describe('randomizeNodes', () => {
it('should set randomizeNodes to true when randomizeNodes not explicitly set', () => {
apiClient = new APIClient(defaultNodes, {
randomizeNodes: undefined,
});
return expect(apiClient).to.have.property('randomizeNodes').be.true;
});
it('should set randomizeNodes to true on initialization when passed as an option', () => {
apiClient = new APIClient(defaultNodes, {
randomizeNodes: true,
});
return expect(apiClient).to.have.property('randomizeNodes').be.true;
});
it('should set randomizeNodes to false on initialization when passed as an option', () => {
apiClient = new APIClient(defaultNodes, {
randomizeNodes: false,
});
return expect(apiClient).to.have.property('randomizeNodes').be.false;
});
});
});
describe('#getNewNode', () => {
it('should throw an error if all relevant nodes are banned', () => {
apiClient.bannedNodes = [...defaultNodes];
return expect(apiClient.getNewNode.bind(apiClient)).to.throw(
'Cannot get new node: all nodes have been banned.',
);
});
it('should return a node', () => {
const result = apiClient.getNewNode();
return expect(defaultNodes).to.contain(result);
});
it('should randomly select the node', () => {
const firstResult = apiClient.getNewNode();
let nextResult = apiClient.getNewNode();
// Test will almost certainly time out if not random
while (nextResult === firstResult) {
nextResult = apiClient.getNewNode();
}
return Promise.resolve();
});
});
describe('#banNode', () => {
it('should add node to banned nodes', () => {
const banned = apiClient.banNode(localNode);
expect(banned).to.be.true;
return expect(apiClient.isBanned(localNode)).to.be.true;
});
it('should not duplicate a banned node', () => {
const bannedNodes = [localNode];
apiClient.bannedNodes = bannedNodes;
const banned = apiClient.banNode(localNode);
expect(banned).to.be.false;
return expect(apiClient.bannedNodes).to.be.eql(bannedNodes);
});
});
describe('#banActiveNode', () => {
let currentNode: string;
beforeEach(() => {
({ currentNode } = apiClient);
return Promise.resolve();
});
it('should add current node to banned nodes', () => {
const banned = apiClient.banActiveNode();
expect(banned).to.be.true;
return expect(apiClient.isBanned(currentNode)).to.be.true;
});
it('should not duplicate a banned node', () => {
const bannedNodes = [currentNode];
apiClient.bannedNodes = bannedNodes;
const banned = apiClient.banActiveNode();
expect(banned).to.be.false;
return expect(apiClient.bannedNodes).to.be.eql(bannedNodes);
});
});
describe('#banActiveNodeAndSelect', () => {
let currentNode: string;
let getNewNodeStub: () => string;
beforeEach(() => {
({ currentNode } = apiClient);
getNewNodeStub = sandbox
.stub(apiClient, 'getNewNode')
.returns(defaultSelectedNode);
return Promise.resolve();
});
it('should call ban current node', () => {
apiClient.banActiveNodeAndSelect();
return expect(apiClient.isBanned(currentNode)).to.be.true;
});
it('should call selectNewNode when the node is banned', () => {
apiClient.banActiveNodeAndSelect();
return expect(getNewNodeStub).to.be.calledOnce;
});
it('should not call selectNewNode when the node is not banned', () => {
const bannedNodes = [currentNode];
apiClient.bannedNodes = bannedNodes;
apiClient.banActiveNodeAndSelect();
return expect(getNewNodeStub).not.to.be.called;
});
});
describe('#isBanned', () => {
it('should return true when provided node is banned', () => {
apiClient.bannedNodes = [...apiClient.bannedNodes, localNode];
return expect(apiClient.isBanned(localNode)).to.be.true;
});
it('should return false when provided node is not banned', () => {
return expect(apiClient.isBanned(localNode)).to.be.false;
});
});
describe('#hasAvailableNodes', () => {
it('should return false without nodes left', () => {
apiClient.bannedNodes = [...defaultNodes];
const result = apiClient.hasAvailableNodes();
return expect(result).to.be.false;
});
it('should return true if nodes are available', () => {
const result = apiClient.hasAvailableNodes();
return expect(result).to.be.true;
});
});
});
================================================
FILE: packages/lisk-api-client/test/api_method.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { apiMethod } from '../src/api_method';
import { Resource, APIHandler } from '../src/api_types';
describe('API method module', () => {
const GET = 'GET';
const POST = 'POST';
const defaultBasePath = 'http://localhost:1234/api';
const defaultResourcePath = '/resources';
const defaultFullPath = `${defaultBasePath}${defaultResourcePath}`;
const defaultHeaders = {
'Content-Type': 'application/json',
nethash: 'mainnetHash',
os: 'lisk-elements-api',
version: '1.0.0',
minVersion: '>=0.5.0',
port: '443',
};
const errorArgumentNumber =
'This endpoint must be supplied with the following parameters: related,id';
const firstURLParam = 'r-123';
const secondURLParam = 123;
let resource: Resource;
let requestResult: object;
let handler: APIHandler;
let validationError: Error;
beforeEach(() => {
requestResult = { success: true, sendRequest: true };
resource = {
path: defaultResourcePath,
resourcePath: defaultFullPath,
headers: defaultHeaders,
request: sandbox.stub().resolves(requestResult),
};
validationError = new Error('No data');
return Promise.resolve();
});
describe('#apiMethod', () => {
describe('when no parameters are passed', () => {
beforeEach(() => {
handler = apiMethod().bind(resource);
return Promise.resolve();
});
it('should return function', () => {
return expect(handler).to.be.a('function');
});
it('should request GET with default URL', () => {
return handler().then(() => {
expect(resource.request).to.be.calledOnce;
return expect(resource.request).to.be.calledWithExactly(
{
method: GET,
url: defaultFullPath,
headers: defaultHeaders,
},
false,
);
});
});
});
describe('when initialized with POST / parameters', () => {
const parameterStringError = 'Parameter must be a string or a number';
beforeEach(() => {
handler = apiMethod({
method: POST,
path: '/{related}/ids/{id}',
urlParams: ['related', 'id'],
validator: data => {
if (!data.needed) {
throw validationError;
}
},
defaultData: {
sort: 'id',
},
retry: true,
}).bind(resource);
return Promise.resolve();
});
it('should return function', () => {
return expect(handler).to.be.a('function');
});
it('should be rejected with error without param', () => {
return expect(handler()).to.be.rejectedWith(Error, errorArgumentNumber);
});
it('should be rejected with error without enough param', () => {
return expect(handler(firstURLParam)).to.be.rejectedWith(
Error,
errorArgumentNumber,
);
});
it('should throw an error if input is not a string or a number', () => {
return expect(
handler({ num: 3 }, secondURLParam, { needed: true }),
).to.be.rejectedWith(Error, parameterStringError);
});
it('should be rejected with no data', () => {
return expect(
handler(firstURLParam, secondURLParam),
).to.be.rejectedWith(validationError);
});
it('should call request with the given data', () => {
return handler(firstURLParam, secondURLParam, { needed: true }).then(
() => {
expect(resource.request).to.be.calledOnce;
return expect(resource.request).to.be.calledWithExactly(
{
method: POST,
url: `${defaultFullPath}/${firstURLParam}/ids/${secondURLParam}`,
headers: defaultHeaders,
data: {
needed: true,
sort: 'id',
},
},
true,
);
},
);
});
});
describe('when initialized with GET / parameters', () => {
beforeEach(() => {
handler = apiMethod({
method: GET,
path: '/{related}/ids/{id}',
urlParams: ['related', 'id'],
validator: data => {
if (!data.needed) {
throw validationError;
}
},
defaultData: {
sort: 'id',
},
}).bind(resource);
return Promise.resolve();
});
it('should return a function', () => {
return expect(handler).to.be.a('function');
});
it('should be rejected with error without parameters', () => {
return expect(handler()).to.be.rejectedWith(Error, errorArgumentNumber);
});
it('should be rejected with error without enough parameters', () => {
return expect(handler(firstURLParam)).to.be.rejectedWith(
Error,
errorArgumentNumber,
);
});
it('should be rejected with no data', () => {
return expect(
handler(firstURLParam, secondURLParam),
).to.be.rejectedWith(validationError);
});
it('should be request with the given data', () => {
return handler(firstURLParam, secondURLParam, { needed: true }).then(
() => {
expect(resource.request).to.be.calledOnce;
return expect(resource.request).to.be.calledWithExactly(
{
method: GET,
url: `${defaultFullPath}/${firstURLParam}/ids/${secondURLParam}?sort=id&needed=true`,
headers: defaultHeaders,
},
false,
);
},
);
});
});
});
});
================================================
FILE: packages/lisk-api-client/test/api_resource.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../src/api_client';
import { APIResource } from '../src/api_resource';
import sinon from 'sinon';
// Required for stub
const axios = require('axios');
describe('API resource module', () => {
const GET = 'GET';
const defaultBasePath = 'http://localhost:1234';
const defaultResourcePath = '/resources';
const defaultFullPath = `${defaultBasePath}/api${defaultResourcePath}`;
const defaultHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
nethash: 'mainnetHash',
os: 'lisk-elements-api',
version: '1.0.0',
minVersion: '>=0.5.0',
port: '443',
};
const defaultRequest = {
method: GET,
url: defaultFullPath,
headers: defaultHeaders,
};
const sendRequestResult = {
data: [],
body: {},
limit: 0,
};
interface FakeAPIClient {
headers: object;
currentNode: string;
hasAvailableNodes: () => boolean | void;
randomizeNodes: boolean;
banActiveNodeAndSelect: () => void;
}
let resource: APIResource;
let apiClient: FakeAPIClient;
beforeEach(() => {
apiClient = {
headers: { ...defaultHeaders },
currentNode: defaultBasePath,
hasAvailableNodes: () => true,
randomizeNodes: false,
banActiveNodeAndSelect: sandbox.stub(),
};
resource = new APIResource(apiClient as APIClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should create an API resource instance', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
});
describe('get headers', () => {
it('should return header set to apiClient', () => {
return expect(resource.headers).to.eql(defaultHeaders);
});
});
describe('get resourcePath', () => {
it('should return the resource’s full path', () => {
return expect(resource.resourcePath).to.equal(`${defaultBasePath}/api`);
});
it('should return the resource’s full path with set path', () => {
resource.path = defaultResourcePath;
return expect(resource.resourcePath).to.equal(
`${defaultBasePath}/api${defaultResourcePath}`,
);
});
});
describe('#request', () => {
let requestStub: sinon.SinonStub;
let handleRetryStub: () => Promise;
beforeEach(() => {
requestStub = sandbox.stub(axios, 'request').resolves({
status: 200,
data: sendRequestResult,
});
handleRetryStub = sandbox.stub(resource, 'handleRetry');
return Promise.resolve();
});
it('should make a request to API without calling retry', () => {
return resource.request(defaultRequest, false).then(res => {
expect(requestStub).to.be.calledOnce;
expect(requestStub).to.be.calledWithExactly(defaultRequest);
expect(handleRetryStub).not.to.be.called;
return expect(res).to.eql(sendRequestResult);
});
});
it('should make a request to API without calling retry when it succeeds', () => {
return resource.request(defaultRequest, true).then(res => {
expect(requestStub).to.be.calledOnce;
expect(requestStub).to.be.calledWithExactly(defaultRequest);
expect(handleRetryStub).not.to.be.called;
return expect(res).to.eql(sendRequestResult);
});
});
describe('when response status is greater than 300', () => {
it('should reject with errno if status code is supplied', () => {
const statusCode = 300;
requestStub.rejects({
response: {
status: statusCode,
data: undefined,
},
});
return resource.request(defaultRequest, false).catch(err => {
return expect(err.errno).to.equal(statusCode);
});
});
it('should reject with "An unknown error has occured." message if there is no data is supplied', () => {
const statusCode = 300;
requestStub.rejects({
response: {
status: statusCode,
data: undefined,
},
});
return resource.request(defaultRequest, false).catch(err => {
return expect(err.message).to.equal('An unknown error has occurred.');
});
});
it('should reject with "An unknown error has occured." message if there is no message is supplied', () => {
const statusCode = 300;
requestStub.rejects({
response: {
status: statusCode,
data: sendRequestResult,
},
});
return resource.request(defaultRequest, false).catch(err => {
return expect(err.message).to.equal('An unknown error has occurred.');
});
});
it('should reject with error message from server if message is supplied', () => {
const serverErrorMessage = 'validation error';
const statusCode = 300;
requestStub.rejects({
response: {
status: statusCode,
data: { message: serverErrorMessage },
},
});
return resource.request(defaultRequest, false).catch(err => {
return expect(err.message).to.eql(serverErrorMessage);
});
});
it('should reject with error message from server if message is undefined and error is supplied', () => {
const serverErrorMessage = 'error from server';
const statusCode = 300;
requestStub.rejects({
response: {
status: statusCode,
data: { message: undefined, error: serverErrorMessage },
},
});
return resource.request(defaultRequest, false).catch(err => {
return expect(err.message).to.eql(serverErrorMessage);
});
});
it('should reject with errors from server if errors are supplied', () => {
const serverErrorMessage = 'validation error';
const statusCode = 300;
const errors = [
{
code: 'error_code_1',
message: 'message1',
},
{
code: 'error_code_2',
message: 'message2',
},
];
requestStub.rejects({
response: {
status: statusCode,
data: { message: serverErrorMessage, errors },
},
});
return resource.request(defaultRequest, false).catch(err => {
return expect(err.errors).to.eql(errors);
});
});
it('should reject with error if client rejects with plain error', () => {
const clientError = new Error('client error');
requestStub.rejects(clientError);
return resource.request(defaultRequest, false).catch(err => {
return expect(err).to.eql(clientError);
});
});
it('should make a request to API with calling retry', () => {
const statusCode = 300;
requestStub.rejects({
response: {
status: statusCode,
data: sendRequestResult,
},
});
return resource.request(defaultRequest, true).catch(() => {
expect(requestStub).to.be.calledOnce;
return expect(handleRetryStub).to.be.calledOnce;
});
});
});
});
describe('#handleRetry', () => {
let requestStub: sinon.SinonStub;
let defaultError: Error;
beforeEach(() => {
defaultError = new Error('could not connect to a node');
requestStub = sandbox
.stub(resource, 'request')
.returns(Promise.resolve(sendRequestResult.body));
return Promise.resolve();
});
describe('when there is available node', () => {
let clock: sinon.SinonFakeTimers;
beforeEach(() => {
clock = sinon.useFakeTimers();
apiClient.hasAvailableNodes = () => true;
return Promise.resolve();
});
afterEach(() => {
return clock.restore();
});
it('should call banActiveNode when randomizeNodes is true', () => {
apiClient.randomizeNodes = true;
const req = resource.handleRetry(defaultError, defaultRequest, 1);
clock.tick(1000);
return req.then(res => {
expect(apiClient.banActiveNodeAndSelect).to.be.calledOnce;
expect(requestStub).to.be.calledWith(defaultRequest, true);
return expect(res).to.be.eql(sendRequestResult.body);
});
});
it('should not call ban active node when randomizeNodes is false', () => {
apiClient.randomizeNodes = false;
const req = resource.handleRetry(defaultError, defaultRequest, 1);
clock.tick(1000);
return req.then(res => {
expect(apiClient.banActiveNodeAndSelect).not.to.be.called;
expect(requestStub).to.be.calledWith(defaultRequest, true);
return expect(res).to.be.eql(sendRequestResult.body);
});
});
it('should throw an error when randomizeNodes is false and the maximum retry count has been reached', () => {
apiClient.randomizeNodes = false;
const req = resource.handleRetry(defaultError, defaultRequest, 4);
clock.tick(1000);
return expect(req).to.be.rejectedWith(defaultError);
});
});
describe('when there is no available node', () => {
beforeEach(() => {
apiClient.hasAvailableNodes = () => false;
return Promise.resolve();
});
it('should throw an error that is the same as input error', () => {
const res = resource.handleRetry(defaultError, defaultRequest, 1);
return expect(res).to.be.rejectedWith(defaultError);
});
});
});
});
================================================
FILE: packages/lisk-api-client/test/constants.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { GET, POST, PUT, TESTNET_NODES, MAINNET_NODES } from '../src/constants';
describe('api constants module', () => {
it('GET should be a string', () => {
return expect(GET).to.be.a('string');
});
it('POST should be a string', () => {
return expect(POST).to.be.a('string');
});
it('PUT should be a string', () => {
return expect(PUT).to.be.a('string');
});
it('TESTNET_NODES should be an array of strings', () => {
expect(TESTNET_NODES).to.be.an('array');
return TESTNET_NODES.forEach(node => expect(node).to.be.a('string'));
});
it('MAINNET_NODES should be an array of strings', () => {
expect(MAINNET_NODES).to.be.an('array');
return MAINNET_NODES.forEach(node => expect(node).to.be.a('string'));
});
});
================================================
FILE: packages/lisk-api-client/test/errors.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIError, APIErrorData } from '../src/errors';
describe('api errors module', () => {
let apiError: APIError;
const defaultMessage = 'this is an error';
const defaultErrno = 401;
beforeEach(() => {
apiError = new APIError();
return Promise.resolve();
});
describe('#constructor', () => {
it('should create a new instance of APIError', () => {
return expect(apiError)
.to.be.an('object')
.and.be.instanceof(APIError);
});
it('should set error name to `APIError`', () => {
return expect(apiError.name).to.eql('APIError');
});
it('should set error message to empty string by default', () => {
return expect(apiError.message).to.eql('');
});
it('should set errno to 500 by default', () => {
return expect(apiError.errno).to.eql(500);
});
describe('when passed errno', () => {
beforeEach(() => {
apiError = new APIError(defaultMessage, defaultErrno);
return Promise.resolve();
});
it('should set error message when passed through first argument', () => {
return expect(apiError.message).to.eql(defaultMessage);
});
it('should set errno when passed through second argument', () => {
return expect(apiError.errno).to.eql(defaultErrno);
});
});
describe('when passed errno and errors', () => {
const errors = [
{
code: 'error_code_1',
message: 'message1',
},
{
code: 'error_code_2',
message: 'message2',
},
];
beforeEach(() => {
apiError = new APIError(defaultMessage, defaultErrno, errors);
return Promise.resolve();
});
it('should set error message when passed through first argument', () => {
return expect(apiError.message).to.eql(defaultMessage);
});
it('should set errno when passed through second argument', () => {
return expect(apiError.errno).to.eql(defaultErrno);
});
it('should set errors when passed through third argument', () => {
expect(apiError.errors).to.have.lengthOf(2);
const errorData = apiError.errors as ReadonlyArray;
expect(errorData[0].code).to.equal(errors[0].code);
return expect(errorData[0].message).to.equal(errors[0].message);
});
});
});
});
================================================
FILE: packages/lisk-api-client/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '../src';
import { expect } from 'chai';
describe('api client', () => {
describe('exports', () => {
it('should have APIClient as a function', () => {
return expect(APIClient).to.be.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/mocha.opts
================================================
--recursive
--require ts-node/register
--require tsconfig-paths/register
--require source-map-support/register
--require ./test/_setup.ts
--file ./test/_global_hooks.ts
--watch-extensions ts
================================================
FILE: packages/lisk-api-client/test/resources/accounts.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { AccountsResource } from '../../src/resources/accounts';
describe('AccountsResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/accounts';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new AccountsResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
it('should have a "getMultisignatureGroups" function', () => {
return expect(resource)
.to.have.property('getMultisignatureGroups')
.which.is.a('function');
});
it('should have a "getMultisignatureMemberships" function', () => {
return expect(resource)
.to.have.property('getMultisignatureMemberships')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/blocks.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { BlocksResource } from '../../src/resources/blocks';
describe('BlocksResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/blocks';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new BlocksResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/dapps.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { DappsResource } from '../../src/resources/dapps';
describe('DappsResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/dapps';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new DappsResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/delegates.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { DelegatesResource } from '../../src/resources/delegates';
describe('DelegatesResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/delegates';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new DelegatesResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
it('should have a "getStandby" function', () => {
return expect(resource)
.to.have.property('getStandby')
.which.is.a('function');
});
it('should have a "getForgers" function', () => {
return expect(resource)
.to.have.property('getForgers')
.which.is.a('function');
});
it('should have a "getForgingStatistics" function', () => {
return expect(resource)
.to.have.property('getForgingStatistics')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/node.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { NodeResource } from '../../src/resources/node';
describe('NodeResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/node';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new NodeResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "getConstants" function', () => {
return expect(resource)
.to.have.property('getConstants')
.which.is.a('function');
});
it('should have a "getStatus" function', () => {
return expect(resource)
.to.have.property('getStatus')
.which.is.a('function');
});
it('should have a "getForgingStatus" function', () => {
return expect(resource)
.to.have.property('getForgingStatus')
.which.is.a('function');
});
it('should have a "updateForgingStatus" function', () => {
return expect(resource)
.to.have.property('updateForgingStatus')
.which.is.a('function');
});
it('should have a "getTransactions" function', () => {
return expect(resource)
.to.have.property('getTransactions')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/peers.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { PeersResource } from '../../src/resources/peers';
describe('PeersResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/peers';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new PeersResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/signatures.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { SignaturesResource } from '../../src/resources/signatures';
describe('SignaturesResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/signatures';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new SignaturesResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "broadcast" function', () => {
return expect(resource)
.to.have.property('broadcast')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/transactions.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { TransactionsResource } from '../../src/resources/transactions';
describe('TransactionsResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/transactions';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new TransactionsResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
it('should have a "broadcast" function', () => {
return expect(resource)
.to.have.property('broadcast')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/voters.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { VotersResource } from '../../src/resources/voters';
describe('VotersResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/voters';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new VotersResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/resources/votes.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { APIClient } from '../../src/api_client';
import { APIResource } from '../../src/api_resource';
import { VotesResource } from '../../src/resources/votes';
describe('VotesResource', () => {
const defaultBasePath = 'http://localhost:1234';
const path = '/votes';
let apiClient: APIClient;
let resource: APIResource;
beforeEach(() => {
apiClient = new APIClient([defaultBasePath]);
resource = new VotesResource(apiClient);
return Promise.resolve();
});
describe('#constructor', () => {
it('should be instance of APIResource', () => {
return expect(resource).to.be.instanceOf(APIResource);
});
it('should have correct full path', () => {
return expect(resource.resourcePath).to.eql(
`${defaultBasePath}/api${path}`,
);
});
it('should set resource path', () => {
return expect(resource.path).to.equal(path);
});
it('should have a "get" function', () => {
return expect(resource)
.to.have.property('get')
.which.is.a('function');
});
});
});
================================================
FILE: packages/lisk-api-client/test/utils.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { toQueryString, solveURLParams } from '../src/utils';
describe('api utils module', () => {
const defaultURL = 'http://localhost:8080/api/resources';
describe('#toQueryString', () => {
it('should create a query string from an object', () => {
const queryString = toQueryString({
key1: 'value1',
key2: 'value2',
key3: 'value3',
});
return expect(queryString).to.be.equal(
'key1=value1&key2=value2&key3=value3',
);
});
it('should escape invalid special characters', () => {
const queryString = toQueryString({
'key:/;?': 'value:/;?',
});
return expect(queryString).to.be.equal(
'key%3A%2F%3B%3F=value%3A%2F%3B%3F',
);
});
});
describe('#solveURLParams', () => {
it('should return original URL with no param', () => {
const solvedURL = solveURLParams(defaultURL);
return expect(solvedURL).to.be.equal(defaultURL);
});
it('should throw error if url has variable but no param', () => {
return expect(solveURLParams.bind(null, `${defaultURL}/{id}`)).to.throw(
Error,
'URL is not completely solved',
);
});
it('should throw error if url has variable but not matching params', () => {
return expect(
solveURLParams.bind(null, `${defaultURL}/{id}`, { accountId: '123' }),
).to.throw(Error, 'URL is not completely solved');
});
it('should replace variable with correct id', () => {
const solvedURL = solveURLParams(`${defaultURL}/{id}`, {
id: '456',
accountId: '123',
});
return expect(solvedURL).to.be.equal(`${defaultURL}/456`);
});
it('should replace multiple variables with correct id and accountId', () => {
const solvedURL = solveURLParams(`${defaultURL}/{accountId}/{id}`, {
id: '456',
accountId: '123',
});
return expect(solvedURL).to.be.equal(`${defaultURL}/123/456`);
});
it('should replace variable with correct id and encode special characters', () => {
const solvedURL = solveURLParams(`${defaultURL}/{id}`, {
id: '456ß1234sd',
accountId: '123',
});
return expect(solvedURL).to.be.equal(`${defaultURL}/456%C3%9F1234sd`);
});
});
});
================================================
FILE: packages/lisk-client/README.md
================================================
# @liskhq/lisk-client
A default set of Elements for use by clients of the Lisk network
## Installation
### Installation via npm
Add Lisk Client as a dependency of your project:
```sh
$ npm install --save @liskhq/lisk-client
```
Import using ES6 modules syntax:
```js
import lisk from '@liskhq/lisk-client';
```
Or using Node.js modules:
```js
const lisk = require('@liskhq/lisk-client');
```
Or import specific namespaced functionality:
```js
import { APIClient, transactions } from '@liskhq/lisk-client';
// or
const { APIClient, transactions } = require('@liskhq/lisk-client');
```
### Installation via CDN
Include the following script using the following HTML. The `lisk` variable will be exposed.
```html
```
Or minified:
```html
```
## Packages
| Package | Version | Description |
| ------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------ |
| [@liskhq/lisk-api-client](../lisk-api-client) | [](https://www.npmjs.com/package/@liskhq/lisk-api-client) | An API client for the Lisk network |
| [@liskhq/lisk-constants](../lisk-constants) | [](https://www.npmjs.com/package/@liskhq/lisk-constants) | General constants for use with Lisk-related software |
| [@liskhq/lisk-cryptography](../lisk-cryptography) | [](https://www.npmjs.com/package/@liskhq/lisk-cryptography) | General cryptographic functions for use with Lisk-related software |
| [@liskhq/lisk-passphrase](../lisk-passphrase) | [](https://www.npmjs.com/package/@liskhq/lisk-passphrase) | Mnemonic passphrase helpers for use with Lisk-related software |
| [@liskhq/lisk-transactions](../lisk-transactions) | [](https://www.npmjs.com/package/@liskhq/lisk-transactions) | Everything related to transactions according to the Lisk protocol |
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-client/index.html
================================================
Title
Open the console to get started with Lisk Client.
================================================
FILE: packages/lisk-client/package.json
================================================
{
"name": "@liskhq/lisk-client",
"version": "2.0.0",
"description": "A default set of Elements for use by clients of the Lisk network",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-client#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"prestart": "./scripts/prestart.sh",
"start": "./scripts/start.sh",
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s lisk",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js -o ./browsertest.build/browsertest.js -s lisk",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{js,json}\" \"{src,test}/**/*.{js,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/**/*.ts test/**/**/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11546 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11546) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11546 && cypress run --config baseUrl=http://localhost:11546 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "NODE_ENV=test nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@liskhq/lisk-api-client": "2.0.0",
"@liskhq/lisk-constants": "1.2.0",
"@liskhq/lisk-cryptography": "2.0.0",
"@liskhq/lisk-passphrase": "2.0.0",
"@liskhq/lisk-transactions": "2.0.0",
"@types/node": "10.10.1"
},
"devDependencies": {
"@types/chai": "4.1.5",
"@types/expect": "1.20.3",
"@types/jquery": "3.3.22",
"@types/mocha": "5.2.5",
"browserify": "16.2.2",
"chai": "4.1.2",
"cypress": "3.1.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-client/scripts/prestart.sh
================================================
read -r -p $'\e[96mDo you want to build Lisk Client first? [y/N]\e[0m ' should_build
if [[ $should_build =~ ^[Yy]$ ]]
then
npm run build:node
fi
================================================
FILE: packages/lisk-client/scripts/start.sh
================================================
node -i -e "global.lisk = require('./dist-node').default; console.log('\\x1b[34m', 'The global \`lisk\` was initialised', '\\x1b[0m')"
================================================
FILE: packages/lisk-client/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient as APIClientModule } from '@liskhq/lisk-api-client';
import * as constantsModule from '@liskhq/lisk-constants';
import * as cryptographyModule from '@liskhq/lisk-cryptography';
import * as passphraseModule from '@liskhq/lisk-passphrase';
import * as transactionModule from '@liskhq/lisk-transactions';
// tslint:disable-next-line variable-name
export const APIClient = APIClientModule;
export const constants = constantsModule;
export const cryptography = cryptographyModule;
export const passphrase = passphraseModule;
export const transaction = transactionModule;
// tslint:disable-next-line no-default-export
export default {
APIClient,
constants,
cryptography,
passphrase,
transaction,
};
================================================
FILE: packages/lisk-client/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import 'chai/register-expect';
process.env.NODE_ENV = 'test';
================================================
FILE: packages/lisk-client/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
APIClient,
constants,
cryptography,
passphrase,
transaction,
} from '../src';
describe('lisk-client', () => {
it('APIClient should be a function', () => {
return expect(APIClient).to.be.a('function');
});
it('constants should be an object', () => {
return expect(constants).to.be.an('object');
});
it('cryptography should be an object', () => {
return expect(cryptography).to.be.an('object');
});
it('passphrase should be an object', () => {
return expect(passphrase).to.be.an('object');
});
it('transaction should be an object', () => {
return expect(transaction).to.be.an('object');
});
});
================================================
FILE: packages/lisk-constants/.gitignore
================================================
# Compiled files
src/**/*.js
test/**/*.js
================================================
FILE: packages/lisk-constants/LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: packages/lisk-constants/README.md
================================================
# lisk-constants
@liskhq/lisk-constants is containing general constants for use with Lisk-related software
## Installation
```sh
$ npm install --save @liskhq/lisk-constants
```
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-constants/package.json
================================================
{
"name": "@liskhq/lisk-constants",
"version": "1.2.0",
"description": "General constants for use with Lisk-related software",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-constants#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s liskConstants",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js -o ./browsertest.build/browsertest.js -s liskConstants",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{ts,js,json}\" \"{src,test}/**/*.{ts,js,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/**/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11542 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11542) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11542 && cypress run --config baseUrl=http://localhost:11542 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@types/node": "10.10.1"
},
"devDependencies": {
"@types/chai": "4.1.5",
"@types/expect": "1.20.3",
"@types/jquery": "3.3.9",
"@types/mocha": "5.2.5",
"browserify": "16.2.2",
"chai": "4.1.2",
"cypress": "3.1.0",
"eslint": "5.5.0",
"eslint-config-airbnb-base": "13.1.0",
"eslint-config-lisk-base": "1.0.0",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-mocha": "5.2.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-constants/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
// tslint:disable-next-line:no-magic-numbers
export const EPOCH_TIME = new Date(Date.UTC(2016, 4, 24, 17, 0, 0, 0));
export const EPOCH_TIME_MILLISECONDS = EPOCH_TIME.getTime();
const MS_FACTOR = 1000;
export const EPOCH_TIME_SECONDS = Math.floor(EPOCH_TIME.getTime() / MS_FACTOR);
// Largest possible number which can be stored in eight bytes.
// Derived from bignum.fromBuffer(Buffer.from(new Array(8).fill(255))).
const MAX_EIGHT_BYTE_NUMBER = '18446744073709551615';
export const MAX_ADDRESS_NUMBER = MAX_EIGHT_BYTE_NUMBER;
export const MAX_TRANSACTION_ID = MAX_EIGHT_BYTE_NUMBER;
// Largest possible amount. Maximum value for PostgreSQL bigint.
export const MAX_TRANSACTION_AMOUNT = '9223372036854775807';
export const SIGNED_MESSAGE_PREFIX = 'Lisk Signed Message:\n';
export const TESTNET_NETHASH =
'da3ed6a45429278bac2666961289ca17ad86595d33b31037615d4b8e8f158bba';
export const MAINNET_NETHASH =
'ed14889723f24ecc54871d058d98ce91ff2f973192075c0155ba2b7b70ad2511';
================================================
FILE: packages/lisk-constants/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { Assertion } from 'chai';
process.env.NODE_ENV = 'test';
Assertion.addProperty('hexString', function handleAssert(
this: Chai.ChaiStatic,
) {
const actual = this._obj;
new Assertion(actual).to.be.a('string');
const expected = Buffer.from(actual, 'hex').toString('hex');
this.assert(
expected === actual,
'expected #{this} to be a hexString',
'expected #{this} not to be a hexString',
);
});
Assertion.addProperty('integer', function handleAssert(this: Chai.ChaiStatic) {
const actual = this._obj;
new Assertion(actual).to.be.a('number');
const expected = parseInt(actual, 10);
this.assert(
actual === expected,
'expected #{this} to be an integer',
'expected #{this} not to be an integer',
);
});
================================================
FILE: packages/lisk-constants/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
EPOCH_TIME,
EPOCH_TIME_SECONDS,
EPOCH_TIME_MILLISECONDS,
MAX_ADDRESS_NUMBER,
MAX_TRANSACTION_ID,
MAX_TRANSACTION_AMOUNT,
TESTNET_NETHASH,
MAINNET_NETHASH,
SIGNED_MESSAGE_PREFIX,
} from '../src';
describe('lisk-constants', () => {
it('EPOCH_TIME should be a Date instance', () => {
return expect(EPOCH_TIME).to.be.instanceOf(Date);
});
it('EPOCH_TIME_SECONDS should be an integer', () => {
return expect(EPOCH_TIME_SECONDS).to.be.an.integer;
});
it('EPOCH_TIME_MILLISECONDS should be an integer', () => {
return expect(EPOCH_TIME_MILLISECONDS).to.be.an.integer;
});
it('MAX_ADDRESS_NUMBER should be a string', () => {
return expect(MAX_ADDRESS_NUMBER).to.be.a('string');
});
it('MAX_TRANSACTION_ID should be a string', () => {
return expect(MAX_TRANSACTION_ID).to.be.a('string');
});
it('MAX_TRANSACTION_AMOUNT should be a string', () => {
return expect(MAX_TRANSACTION_AMOUNT).to.be.a('string');
});
it('TESTNET_NETHASH should be a string', () => {
return expect(TESTNET_NETHASH).to.be.a.hexString;
});
it('MAINNET_NETHASH should be a string', () => {
return expect(MAINNET_NETHASH).to.be.a.hexString;
});
it('SIGNED_MESSAGE_PREFIX should be a string', () => {
return expect(SIGNED_MESSAGE_PREFIX).to.be.a('string');
});
});
================================================
FILE: packages/lisk-cryptography/LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: packages/lisk-cryptography/README.md
================================================
# @liskhq/lisk-cryptography
@liskhq/lisk-cryptography is containing general cryptographic functions for use with Lisk-related software
## Installation
```sh
$ npm install --save @liskhq/lisk-cryptography
```
## Benchmarking
Install optional dependencies:
```sh
$ npm i -D benchmark sodium-native
```
Benchmark nacl functions:
```sh
$ npx babel-node ./benchmark/nacl
```
Benchmark results for nacl functions:
| Function | Fast | Slow | Winner |
| :-----------------: | :-----------------------:|:-----------------------: | :----: |
| box | x 23,982 ops/sec ±0.59% | x 771 ops/sec ±0.44% | Fast |
| openBox | x 24,247 ops/sec ±0.42% | x 770 ops/sec ±0.69% | Fast |
| signDetached | x 46,402 ops/sec ±0.32% | x 236 ops/sec ±1.63% | Fast |
| verifyDetached | x 17,153 ops/sec ±0.19% | x 122 ops/sec ±0.61% | Fast |
| getRandomBytes | x 207,866 ops/sec ±0.23% | x 299,959 ops/sec ±0.39% | Slow |
| getKeyPair | x 38,815 ops/sec ±0.16% | x 242 ops/sec ±0.62% | Fast |
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-cryptography/benchmark/nacl.js
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import Benchmark from 'benchmark';
import * as fast from '../src/nacl/fast';
import * as slow from '../src/nacl/slow';
Benchmark.options.minSamples = 100;
const defaultPublicKey =
'7ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultPrivateKey =
'314852d7afb0d4c283692fef8a2cb40e30c7a5df2ed79994178c10ac168d6d977ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultMessage = 'Some default text.';
const defaultSignature =
'68937004b6720d7e1902ef05a577e6d9f9ab2756286b1f2ae918f8a0e5153c15e4f410916076f750b708f8979be2430e4cfc7ebb523ae1905d2ea1f5d24ce700';
const defaultEncryptedMessage =
'a232e5ea10e18249efc5a0aa8ed68271fc494d02245c52277ee2e14cddd960144a65';
const defaultNonce = 'df4c8b09e270d2cb3f7b3d53dfa8a6f3441ad3b14a13fb66';
const defaultHash =
'314852d7afb0d4c283692fef8a2cb40e30c7a5df2ed79994178c10ac168d6d97';
const defaultDigest =
'aba8462bb7a1460f1e36c36a71f0b7f67d1606562001907c1b2dad08a8ce74ae';
const defaultConvertedPublicKeyEd2Curve =
'b8c0eecfd16c1cc4f057a6fc6d8dd3d46e4aa9625408d4bd0ba00e991326fe00';
const defaultConvertedPrivateKeyEd2Curve =
'b0e3276b64b086b381e11928e56f966d062dc677b7801cc594aeb2d4193e8d57';
const boxBenchmark = new Benchmark.Suite('box')
.add('fast.box', () => {
fast.box(
Buffer.from(defaultMessage, 'utf8'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
})
.add('slow.box', () => {
slow.box(
Buffer.from(defaultMessage, 'utf8'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
});
const openBoxBenchmark = new Benchmark.Suite('openBox')
.add('fast.openBox', () => {
fast.openBox(
Buffer.from(defaultEncryptedMessage, 'hex'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
})
.add('slow.openBox', () => {
slow.openBox(
Buffer.from(defaultEncryptedMessage, 'hex'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
});
const signDetachedBenchmark = new Benchmark.Suite('signDetached')
.add('fast.signDetached', () => {
fast.signDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultPrivateKey, 'hex'),
);
})
.add('slow.signDetached', () => {
slow.signDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultPrivateKey, 'hex'),
);
});
const verifyDetachedBenchmark = new Benchmark.Suite('verifyDetached')
.add('fast.verifyDetached', () => {
fast.verifyDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultSignature, 'hex'),
Buffer.from(defaultPublicKey, 'hex'),
);
})
.add('slow.verifyDetached', () => {
slow.verifyDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultSignature, 'hex'),
Buffer.from(defaultPublicKey, 'hex'),
);
});
const getRandomBytesBenchmark = new Benchmark.Suite('getRandomBytes')
.add('fast.getRandomBytes', () => {
fast.getRandomBytes(24);
})
.add('slow.getRandomBytes', () => {
slow.getRandomBytes(24);
});
const getKeyPairBenchmark = new Benchmark.Suite('getKeyPair')
.add('fast.getKeyPair', () => {
fast.getKeyPair(Buffer.from(defaultHash, 'hex'));
})
.add('slow.getKeyPair', () => {
slow.getKeyPair(Buffer.from(defaultHash, 'hex'));
});
[
boxBenchmark,
openBoxBenchmark,
signDetachedBenchmark,
verifyDetachedBenchmark,
getRandomBytesBenchmark,
getKeyPairBenchmark,
].forEach(benchmark => {
benchmark
.on('start', () => {
console.info(`Evaluating ${benchmark.name}..`);
})
.on('cycle', event => {
console.info(String(event.target));
})
.on('complete', function callback() {
console.info(`Winner is ${this.filter('fastest').map('name')}!`);
})
.run();
});
================================================
FILE: packages/lisk-cryptography/package.json
================================================
{
"name": "@liskhq/lisk-cryptography",
"version": "2.0.0",
"description": "General cryptographic functions for use with Lisk-related software",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-cryptography#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s liskCryptography",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js -o ./browsertest.build/browsertest.js -s liskCryptography",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{ts,json}\" \"{src,test}/**/*.{ts,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/{,/**/}/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11543 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11543) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11543 && cypress run --config baseUrl=http://localhost:11543 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "NODE_ENV=test nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@types/ed2curve": "0.2.2",
"@types/node": "10.12.0",
"browserify-bignum": "1.3.0-2",
"buffer-reverse": "1.0.1",
"ed2curve": "0.2.1",
"tweetnacl": "1.0.0",
"varuint-bitcoin": "1.1.0"
},
"optionalDependencies": {
"sodium-native": "2.2.1"
},
"devDependencies": {
"@types/jquery": "3.3.22",
"@types/mocha": "5.2.5",
"benchmark": "2.1.4",
"browserify": "16.2.2",
"chai": "4.1.2",
"cypress": "3.1.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"sinon": "6.2.0",
"sodium-native": "2.2.1",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-immutable": "4.8.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-cryptography/src/buffer.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import BigNum from 'browserify-bignum';
export const bigNumberToBuffer = (bignumber: string, size: number) =>
new BigNum(bignumber).toBuffer({ size, endian: 'big' });
export const bufferToBigNumberString = (bigNumberBuffer: Buffer): string =>
BigNum.fromBuffer(bigNumberBuffer).toString();
export const bufferToHex = (buffer: Buffer): string =>
Buffer.from(buffer).toString('hex');
const hexRegex = /^[0-9a-f]+/i;
export const hexToBuffer = (hex: string, argumentName = 'Argument'): Buffer => {
if (typeof hex !== 'string') {
throw new TypeError(`${argumentName} must be a string.`);
}
const matchedHex = (hex.match(hexRegex) || [])[0];
if (!matchedHex || matchedHex.length !== hex.length) {
throw new TypeError(`${argumentName} must be a valid hex string.`);
}
// tslint:disable-next-line no-magic-numbers
if (matchedHex.length % 2 !== 0) {
throw new TypeError(
`${argumentName} must have a valid length of hex string.`,
);
}
return Buffer.from(matchedHex, 'hex');
};
================================================
FILE: packages/lisk-cryptography/src/constants.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export const SIGNED_MESSAGE_PREFIX = 'Lisk Signed Message:\n';
================================================
FILE: packages/lisk-cryptography/src/convert.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import reverseBuffer from 'buffer-reverse';
import ed2curve from 'ed2curve';
import querystring from 'querystring';
import { bufferToBigNumberString } from './buffer';
import { EncryptedPassphraseObject } from './encrypt';
import { hash } from './hash';
export const getFirstEightBytesReversed = (input: string | Buffer): Buffer => {
const BUFFER_SIZE = 8;
// Union type arguments on overloaded functions do not work in typescript.
// Relevant discussion: https://github.com/Microsoft/TypeScript/issues/23155
if (typeof input === 'string') {
return reverseBuffer(Buffer.from(input).slice(0, BUFFER_SIZE));
}
return reverseBuffer(Buffer.from(input).slice(0, BUFFER_SIZE));
};
export const toAddress = (buffer: Buffer): string => {
const BUFFER_SIZE = 8;
if (
!Buffer.from(buffer)
.slice(0, BUFFER_SIZE)
.equals(buffer)
) {
throw new Error(
'The buffer for Lisk addresses must not have more than 8 bytes',
);
}
return `${bufferToBigNumberString(buffer)}L`;
};
export const getAddressFromPublicKey = (publicKey: string): string => {
const publicKeyHash = hash(publicKey, 'hex');
const publicKeyTransform = getFirstEightBytesReversed(publicKeyHash);
const address = toAddress(publicKeyTransform);
return address;
};
export const convertPublicKeyEd2Curve = ed2curve.convertPublicKey;
export const convertPrivateKeyEd2Curve = ed2curve.convertSecretKey;
export const stringifyEncryptedPassphrase = (
encryptedPassphrase: EncryptedPassphraseObject,
): string => {
if (typeof encryptedPassphrase !== 'object' || encryptedPassphrase === null) {
throw new Error('Encrypted passphrase to stringify must be an object.');
}
const objectToStringify = encryptedPassphrase.iterations
? encryptedPassphrase
: {
salt: encryptedPassphrase.salt,
cipherText: encryptedPassphrase.cipherText,
iv: encryptedPassphrase.iv,
tag: encryptedPassphrase.tag,
version: encryptedPassphrase.version,
};
return querystring.stringify(objectToStringify);
};
const parseIterations = (iterationsString?: string): number | undefined => {
const iterations =
iterationsString === undefined ? undefined : parseInt(iterationsString, 10);
if (typeof iterations !== 'undefined' && Number.isNaN(iterations)) {
throw new Error('Could not parse iterations.');
}
return iterations;
};
export const parseEncryptedPassphrase = (
encryptedPassphrase: string,
): EncryptedPassphraseObject => {
if (typeof encryptedPassphrase !== 'string') {
throw new Error('Encrypted passphrase to parse must be a string.');
}
const keyValuePairs = querystring.parse(encryptedPassphrase);
const { iterations, salt, cipherText, iv, tag, version } = keyValuePairs;
// Review, and find a better solution
if (
(typeof iterations !== 'string' && typeof iterations !== 'undefined') ||
typeof salt !== 'string' ||
typeof cipherText !== 'string' ||
typeof iv !== 'string' ||
typeof tag !== 'string' ||
typeof version !== 'string'
) {
throw new Error(
'Encrypted passphrase to parse must have only one value per key.',
);
}
return {
iterations: parseIterations(iterations),
salt,
cipherText,
iv,
tag,
version,
};
};
================================================
FILE: packages/lisk-cryptography/src/encrypt.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import crypto from 'crypto';
import { bufferToHex, hexToBuffer } from './buffer';
import { convertPrivateKeyEd2Curve, convertPublicKeyEd2Curve } from './convert';
import { getPrivateAndPublicKeyBytesFromPassphrase } from './keys';
import { box, getRandomBytes, openBox } from './nacl';
const PBKDF2_ITERATIONS = 1e6;
const PBKDF2_KEYLEN = 32;
const PBKDF2_HASH_FUNCTION = 'sha256';
const ENCRYPTION_VERSION = '1';
export interface EncryptedMessageWithNonce {
readonly encryptedMessage: string;
readonly nonce: string;
}
export const encryptMessageWithPassphrase = (
message: string,
passphrase: string,
recipientPublicKey: string,
): EncryptedMessageWithNonce => {
const {
privateKeyBytes: senderPrivateKeyBytes,
} = getPrivateAndPublicKeyBytesFromPassphrase(passphrase);
const convertedPrivateKey = Buffer.from(
convertPrivateKeyEd2Curve(senderPrivateKeyBytes),
);
const recipientPublicKeyBytes = hexToBuffer(recipientPublicKey);
const messageInBytes = Buffer.from(message, 'utf8');
const nonceSize = 24;
const nonce = getRandomBytes(nonceSize);
const publicKeyUint8Array = convertPublicKeyEd2Curve(recipientPublicKeyBytes);
// This cannot be reproduced, but external library have type union with null
if (publicKeyUint8Array === null) {
throw new Error('given public key is not a valid Ed25519 public key');
}
const convertedPublicKey = Buffer.from(publicKeyUint8Array);
const cipherBytes = box(
messageInBytes,
nonce,
convertedPublicKey,
convertedPrivateKey,
);
const nonceHex = bufferToHex(nonce);
const encryptedMessage = bufferToHex(cipherBytes);
return {
nonce: nonceHex,
encryptedMessage,
};
};
export const decryptMessageWithPassphrase = (
cipherHex: string,
nonce: string,
passphrase: string,
senderPublicKey: string,
): string => {
const {
privateKeyBytes: recipientPrivateKeyBytes,
} = getPrivateAndPublicKeyBytesFromPassphrase(passphrase);
const convertedPrivateKey = Buffer.from(
convertPrivateKeyEd2Curve(recipientPrivateKeyBytes),
);
const senderPublicKeyBytes = hexToBuffer(senderPublicKey);
const cipherBytes = hexToBuffer(cipherHex);
const nonceBytes = hexToBuffer(nonce);
const publicKeyUint8Array = convertPublicKeyEd2Curve(senderPublicKeyBytes);
// This cannot be reproduced, but external library have type union with null
if (publicKeyUint8Array === null) {
throw new Error('given public key is not a valid Ed25519 public key');
}
const convertedPublicKey = Buffer.from(publicKeyUint8Array);
try {
const decoded = openBox(
cipherBytes,
nonceBytes,
convertedPublicKey,
convertedPrivateKey,
);
return Buffer.from(decoded).toString();
} catch (error) {
if (
error.message.match(
/bad nonce size|nonce must be a buffer of size crypto_box_NONCEBYTES/,
)
) {
throw new Error('Expected nonce to be 24 bytes.');
}
throw new Error(
'Something went wrong during decryption. Is this the full encrypted message?',
);
}
};
const getKeyFromPassword = (
password: string,
salt: Buffer,
iterations: number,
): Buffer =>
crypto.pbkdf2Sync(
password,
salt,
iterations,
PBKDF2_KEYLEN,
PBKDF2_HASH_FUNCTION,
);
export interface EncryptedPassphraseObject {
readonly cipherText: string;
readonly iterations?: number;
readonly iv: string;
readonly salt: string;
readonly tag: string;
readonly version: string;
}
const encryptAES256GCMWithPassword = (
plainText: string,
password: string,
iterations: number = PBKDF2_ITERATIONS,
): EncryptedPassphraseObject => {
const IV_BUFFER_SIZE = 12;
const SALT_BUFFER_SIZE = 16;
const iv = crypto.randomBytes(IV_BUFFER_SIZE);
const salt = crypto.randomBytes(SALT_BUFFER_SIZE);
const key = getKeyFromPassword(password, salt, iterations);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const firstBlock = cipher.update(plainText, 'utf8');
const encrypted = Buffer.concat([firstBlock, cipher.final()]);
const tag = cipher.getAuthTag();
return {
iterations,
cipherText: encrypted.toString('hex'),
iv: iv.toString('hex'),
salt: salt.toString('hex'),
tag: tag.toString('hex'),
version: ENCRYPTION_VERSION,
};
};
const getTagBuffer = (tag: string): Buffer => {
const TAG_BUFFER_SIZE = 16;
const tagBuffer = hexToBuffer(tag, 'Tag');
if (tagBuffer.length !== TAG_BUFFER_SIZE) {
throw new Error('Tag must be 16 bytes.');
}
return tagBuffer;
};
const decryptAES256GCMWithPassword = (
encryptedPassphrase: EncryptedPassphraseObject,
password: string,
): string => {
const {
iterations = PBKDF2_ITERATIONS,
cipherText,
iv,
salt,
tag,
} = encryptedPassphrase;
const tagBuffer = getTagBuffer(tag);
const key = getKeyFromPassword(
password,
hexToBuffer(salt, 'Salt'),
iterations,
);
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key,
hexToBuffer(iv, 'IV'),
);
decipher.setAuthTag(tagBuffer);
const firstBlock = decipher.update(hexToBuffer(cipherText, 'Cipher text'));
const decrypted = Buffer.concat([firstBlock, decipher.final()]);
return decrypted.toString();
};
export const encryptPassphraseWithPassword = encryptAES256GCMWithPassword;
export const decryptPassphraseWithPassword = decryptAES256GCMWithPassword;
================================================
FILE: packages/lisk-cryptography/src/hash.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import crypto from 'crypto';
import { hexToBuffer } from './buffer';
const cryptoHashSha256 = (data: Buffer): Buffer => {
const dataHash = crypto.createHash('sha256');
dataHash.update(data);
return dataHash.digest();
};
export const hash = (data: Buffer | string, format?: string): Buffer => {
if (Buffer.isBuffer(data)) {
return cryptoHashSha256(data);
}
if (typeof data === 'string' && typeof format === 'string') {
if (!['utf8', 'hex'].includes(format)) {
throw new Error(
'Unsupported string format. Currently only `hex` and `utf8` are supported.',
);
}
const encoded =
format === 'utf8' ? Buffer.from(data, 'utf8') : hexToBuffer(data);
return cryptoHashSha256(encoded);
}
throw new Error(
'Unsupported data format. Currently only Buffers or `hex` and `utf8` strings are supported.',
);
};
================================================
FILE: packages/lisk-cryptography/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as constants from './constants';
export * from './buffer';
export * from './convert';
export * from './encrypt';
export * from './hash';
export * from './keys';
export * from './sign';
export { constants };
================================================
FILE: packages/lisk-cryptography/src/keys.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { bufferToHex } from './buffer';
import { getAddressFromPublicKey } from './convert';
import { hash } from './hash';
import { getKeyPair } from './nacl';
export interface KeypairBytes {
readonly privateKeyBytes: Buffer;
readonly publicKeyBytes: Buffer;
}
export interface Keypair {
readonly privateKey: string;
readonly publicKey: string;
}
export const getPrivateAndPublicKeyBytesFromPassphrase = (
passphrase: string,
): KeypairBytes => {
const hashed = hash(passphrase, 'utf8');
const { publicKeyBytes, privateKeyBytes } = getKeyPair(hashed);
return {
privateKeyBytes,
publicKeyBytes,
};
};
export const getPrivateAndPublicKeyFromPassphrase = (
passphrase: string,
): Keypair => {
const {
privateKeyBytes,
publicKeyBytes,
} = getPrivateAndPublicKeyBytesFromPassphrase(passphrase);
return {
privateKey: bufferToHex(privateKeyBytes),
publicKey: bufferToHex(publicKeyBytes),
};
};
export const getKeys = getPrivateAndPublicKeyFromPassphrase;
export const getAddressAndPublicKeyFromPassphrase = (
passphrase: string,
): { readonly address: string; readonly publicKey: string } => {
const { publicKey } = getKeys(passphrase);
const address = getAddressFromPublicKey(publicKey);
return {
address,
publicKey,
};
};
export const getAddressFromPassphrase = (passphrase: string): string => {
const { publicKey } = getKeys(passphrase);
return getAddressFromPublicKey(publicKey);
};
================================================
FILE: packages/lisk-cryptography/src/nacl/fast.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
// tslint:disable-next-line no-implicit-dependencies
import sodium from 'sodium-native';
import { NaclInterface } from './nacl_types';
export const box: NaclInterface['box'] = (
messageInBytes,
nonceInBytes,
convertedPublicKey,
convertedPrivateKey,
) => {
const cipherBytes = Buffer.alloc(
messageInBytes.length + sodium.crypto_box_MACBYTES,
);
sodium.crypto_box_easy(
cipherBytes,
messageInBytes,
nonceInBytes,
convertedPublicKey,
convertedPrivateKey,
);
return cipherBytes;
};
export const openBox: NaclInterface['openBox'] = (
cipherBytes,
nonceBytes,
convertedPublicKey,
convertedPrivateKey,
) => {
const plainText = Buffer.alloc(
cipherBytes.length - sodium.crypto_box_MACBYTES,
);
// Returns false if decryption fails
if (
!sodium.crypto_box_open_easy(
plainText,
cipherBytes,
nonceBytes,
convertedPublicKey,
convertedPrivateKey,
)
) {
throw new Error('Failed to decrypt message');
}
return plainText;
};
export const signDetached: NaclInterface['signDetached'] = (
messageBytes,
privateKeyBytes,
) => {
const signatureBytes = Buffer.alloc(sodium.crypto_sign_BYTES);
sodium.crypto_sign_detached(signatureBytes, messageBytes, privateKeyBytes);
return signatureBytes;
};
export const verifyDetached: NaclInterface['verifyDetached'] = (
messageBytes,
signatureBytes,
publicKeyBytes,
) =>
sodium.crypto_sign_verify_detached(
signatureBytes,
messageBytes,
publicKeyBytes,
);
export const getRandomBytes: NaclInterface['getRandomBytes'] = length => {
const nonce = Buffer.alloc(length);
sodium.randombytes_buf(nonce);
return nonce;
};
export const getKeyPair: NaclInterface['getKeyPair'] = hashedSeed => {
const publicKeyBytes = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES);
const privateKeyBytes = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES);
sodium.crypto_sign_seed_keypair(publicKeyBytes, privateKeyBytes, hashedSeed);
return {
publicKeyBytes,
privateKeyBytes,
};
};
================================================
FILE: packages/lisk-cryptography/src/nacl/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { NaclInterface } from './nacl_types';
// tslint:disable-next-line no-let
let lib: NaclInterface;
try {
if (process.env.NACL_FAST === 'disable') {
throw new Error('Use tweetnacl');
}
// Require used for conditional importing
// tslint:disable-next-line no-var-requires no-require-imports
lib = require('./fast');
} catch (err) {
process.env.NACL_FAST = 'disable';
// tslint:disable-next-line no-var-requires no-require-imports
lib = require('./slow');
}
export const NACL_SIGN_PUBLICKEY_LENGTH = 32;
export const NACL_SIGN_SIGNATURE_LENGTH = 64;
export const {
box,
openBox,
signDetached,
verifyDetached,
getRandomBytes,
getKeyPair,
} = lib;
================================================
FILE: packages/lisk-cryptography/src/nacl/nacl_types.ts
================================================
import { KeypairBytes } from '../keys';
export interface NaclInterface {
box(
messageInBytes: Buffer,
nonceInBytes: Buffer,
convertedPublicKey: Buffer,
convertedPrivateKey: Buffer,
): Buffer;
getKeyPair(hashedSeed: Buffer): KeypairBytes;
getRandomBytes(length: number): Buffer;
openBox(
cipherBytes: Buffer,
nonceBytes: Buffer,
convertedPublicKey: Buffer,
convertedPrivateKey: Buffer,
): Buffer;
signDetached(messageBytes: Buffer, privateKeyBytes: Buffer): Buffer;
verifyDetached(
messageBytes: Buffer,
signatureBytes: Buffer,
publicKeyBytes: Buffer,
): boolean;
}
================================================
FILE: packages/lisk-cryptography/src/nacl/slow.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import tweetnacl from 'tweetnacl';
import { NaclInterface } from './nacl_types';
export const box: NaclInterface['box'] = (
messageInBytes,
nonceInBytes,
convertedPublicKey,
convertedPrivateKey,
) =>
Buffer.from(
tweetnacl.box(
messageInBytes,
nonceInBytes,
convertedPublicKey,
convertedPrivateKey,
),
);
export const openBox: NaclInterface['openBox'] = (
cipherBytes,
nonceBytes,
convertedPublicKey,
convertedPrivateKey,
) => {
const originalMessage = tweetnacl.box.open(
cipherBytes,
nonceBytes,
convertedPublicKey,
convertedPrivateKey,
);
// Returns null if decryption fails
if (originalMessage === null) {
throw new Error('Failed to decrypt message');
}
return Buffer.from(originalMessage);
};
export const signDetached: NaclInterface['signDetached'] = (
messageBytes,
privateKeyBytes,
) => Buffer.from(tweetnacl.sign.detached(messageBytes, privateKeyBytes));
export const verifyDetached: NaclInterface['verifyDetached'] =
tweetnacl.sign.detached.verify;
export const getRandomBytes: NaclInterface['getRandomBytes'] = length =>
Buffer.from(tweetnacl.randomBytes(length));
export const getKeyPair: NaclInterface['getKeyPair'] = hashedSeed => {
const { publicKey, secretKey } = tweetnacl.sign.keyPair.fromSeed(hashedSeed);
return {
privateKeyBytes: Buffer.from(secretKey),
publicKeyBytes: Buffer.from(publicKey),
};
};
================================================
FILE: packages/lisk-cryptography/src/sign.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { encode as encodeVarInt } from 'varuint-bitcoin';
import { bufferToHex, hexToBuffer } from './buffer';
import { SIGNED_MESSAGE_PREFIX } from './constants';
import { hash } from './hash';
import { getPrivateAndPublicKeyBytesFromPassphrase } from './keys';
import {
NACL_SIGN_PUBLICKEY_LENGTH,
NACL_SIGN_SIGNATURE_LENGTH,
signDetached,
verifyDetached,
} from './nacl';
const createHeader = (text: string): string => `-----${text}-----`;
const signedMessageHeader = createHeader('BEGIN LISK SIGNED MESSAGE');
const messageHeader = createHeader('MESSAGE');
const publicKeyHeader = createHeader('PUBLIC KEY');
const secondPublicKeyHeader = createHeader('SECOND PUBLIC KEY');
const signatureHeader = createHeader('SIGNATURE');
const secondSignatureHeader = createHeader('SECOND SIGNATURE');
const signatureFooter = createHeader('END LISK SIGNED MESSAGE');
const SIGNED_MESSAGE_PREFIX_BYTES = Buffer.from(SIGNED_MESSAGE_PREFIX, 'utf8');
const SIGNED_MESSAGE_PREFIX_LENGTH = encodeVarInt(SIGNED_MESSAGE_PREFIX.length);
export interface SignedMessageWithOnePassphrase {
readonly message: string;
readonly publicKey: string;
readonly signature: string;
}
export const digestMessage = (message: string): Buffer => {
const msgBytes = Buffer.from(message, 'utf8');
const msgLenBytes = encodeVarInt(message.length);
const dataBytes = Buffer.concat([
SIGNED_MESSAGE_PREFIX_LENGTH,
SIGNED_MESSAGE_PREFIX_BYTES,
msgLenBytes,
msgBytes,
]);
return hash(hash(dataBytes));
};
export const signMessageWithPassphrase = (
message: string,
passphrase: string,
): SignedMessageWithOnePassphrase => {
const msgBytes = digestMessage(message);
const {
privateKeyBytes,
publicKeyBytes,
} = getPrivateAndPublicKeyBytesFromPassphrase(passphrase);
const signature = signDetached(msgBytes, privateKeyBytes);
return {
message,
publicKey: bufferToHex(publicKeyBytes),
signature: bufferToHex(signature),
};
};
export const verifyMessageWithPublicKey = ({
message,
publicKey,
signature,
}: SignedMessageWithOnePassphrase): boolean => {
const msgBytes = digestMessage(message);
const signatureBytes = hexToBuffer(signature);
const publicKeyBytes = hexToBuffer(publicKey);
if (publicKeyBytes.length !== NACL_SIGN_PUBLICKEY_LENGTH) {
throw new Error(
`Invalid publicKey, expected ${NACL_SIGN_PUBLICKEY_LENGTH}-byte publicKey`,
);
}
if (signatureBytes.length !== NACL_SIGN_SIGNATURE_LENGTH) {
throw new Error(
`Invalid signature length, expected ${NACL_SIGN_SIGNATURE_LENGTH}-byte signature`,
);
}
return verifyDetached(msgBytes, signatureBytes, publicKeyBytes);
};
export interface SignedMessageWithTwoPassphrases {
readonly message: string;
readonly publicKey: string;
readonly secondPublicKey: string;
readonly secondSignature: string;
readonly signature: string;
}
export const signMessageWithTwoPassphrases = (
message: string,
passphrase: string,
secondPassphrase: string,
): SignedMessageWithTwoPassphrases => {
const msgBytes = digestMessage(message);
const keypairBytes = getPrivateAndPublicKeyBytesFromPassphrase(passphrase);
const secondKeypairBytes = getPrivateAndPublicKeyBytesFromPassphrase(
secondPassphrase,
);
const signature = signDetached(msgBytes, keypairBytes.privateKeyBytes);
const secondSignature = signDetached(
msgBytes,
secondKeypairBytes.privateKeyBytes,
);
return {
message,
publicKey: bufferToHex(keypairBytes.publicKeyBytes),
secondPublicKey: bufferToHex(secondKeypairBytes.publicKeyBytes),
signature: bufferToHex(signature),
secondSignature: bufferToHex(secondSignature),
};
};
export const verifyMessageWithTwoPublicKeys = ({
message,
signature,
secondSignature,
publicKey,
secondPublicKey,
}: SignedMessageWithTwoPassphrases) => {
const messageBytes = digestMessage(message);
const signatureBytes = hexToBuffer(signature);
const secondSignatureBytes = hexToBuffer(secondSignature);
const publicKeyBytes = hexToBuffer(publicKey);
const secondPublicKeyBytes = hexToBuffer(secondPublicKey);
if (signatureBytes.length !== NACL_SIGN_SIGNATURE_LENGTH) {
throw new Error(
`Invalid first signature length, expected ${NACL_SIGN_SIGNATURE_LENGTH}-byte signature`,
);
}
if (secondSignatureBytes.length !== NACL_SIGN_SIGNATURE_LENGTH) {
throw new Error(
`Invalid second signature length, expected ${NACL_SIGN_SIGNATURE_LENGTH}-byte signature`,
);
}
if (publicKeyBytes.length !== NACL_SIGN_PUBLICKEY_LENGTH) {
throw new Error(
`Invalid first publicKey, expected ${NACL_SIGN_PUBLICKEY_LENGTH}-byte publicKey`,
);
}
if (secondPublicKeyBytes.length !== NACL_SIGN_PUBLICKEY_LENGTH) {
throw new Error(
`Invalid second publicKey, expected ${NACL_SIGN_PUBLICKEY_LENGTH}-byte publicKey`,
);
}
const verifyFirstSignature = () =>
verifyDetached(messageBytes, signatureBytes, publicKeyBytes);
const verifySecondSignature = () =>
verifyDetached(messageBytes, secondSignatureBytes, secondPublicKeyBytes);
return verifyFirstSignature() && verifySecondSignature();
};
export interface SingleOrDoubleSignedMessage {
readonly message: string;
readonly publicKey: string;
readonly secondPublicKey?: string;
readonly secondSignature?: string;
readonly signature: string;
}
export const printSignedMessage = ({
message,
signature,
publicKey,
secondSignature,
secondPublicKey,
}: SingleOrDoubleSignedMessage): string =>
[
signedMessageHeader,
messageHeader,
message,
publicKeyHeader,
publicKey,
secondPublicKey ? secondPublicKeyHeader : undefined,
secondPublicKey,
signatureHeader,
signature,
secondSignature ? secondSignatureHeader : undefined,
secondSignature,
signatureFooter,
]
.filter(Boolean)
.join('\n');
export const signAndPrintMessage = (
message: string,
passphrase: string,
secondPassphrase?: string,
): string => {
const signedMessage:
| SignedMessageWithOnePassphrase
| SignedMessageWithTwoPassphrases = secondPassphrase
? signMessageWithTwoPassphrases(message, passphrase, secondPassphrase)
: signMessageWithPassphrase(message, passphrase);
return printSignedMessage(signedMessage);
};
export const signDataWithPrivateKey = (
data: Buffer,
privateKey: Buffer,
): string => {
const signature = signDetached(data, privateKey);
return bufferToHex(signature);
};
export const signDataWithPassphrase = (
data: Buffer,
passphrase: string,
): string => {
const { privateKeyBytes } = getPrivateAndPublicKeyBytesFromPassphrase(
passphrase,
);
return signDataWithPrivateKey(data, privateKeyBytes);
};
export const signData = signDataWithPassphrase;
export const verifyData = (
data: Buffer,
signature: string,
publicKey: string,
): boolean =>
verifyDetached(data, hexToBuffer(signature), hexToBuffer(publicKey));
================================================
FILE: packages/lisk-cryptography/test/_global_hooks.ts
================================================
afterEach(() => {
return sandbox.restore();
});
================================================
FILE: packages/lisk-cryptography/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { Assertion } from 'chai';
import 'chai/register-expect';
import sinon from 'sinon';
process.env.NODE_ENV = 'test';
Assertion.addProperty('hexString', function handleAssert(
this: Chai.ChaiStatic,
) {
const actual = this._obj;
new Assertion(actual).to.be.a('string');
const expected = Buffer.from(actual, 'hex').toString('hex');
this.assert(
expected === actual,
'expected #{this} to be a hexString',
'expected #{this} not to be a hexString',
);
});
Assertion.addProperty('integer', function handleAssert(this: Chai.ChaiStatic) {
const actual = this._obj;
new Assertion(actual).to.be.a('number');
const expected = parseInt(actual, 10);
this.assert(
actual === expected,
'expected #{this} to be an integer',
'expected #{this} not to be an integer',
);
});
global.sandbox = sinon.createSandbox({
useFakeTimers: true,
});
================================================
FILE: packages/lisk-cryptography/test/buffer.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
bigNumberToBuffer,
bufferToBigNumberString,
bufferToHex,
hexToBuffer,
} from '../src/buffer';
describe('buffer', () => {
const defaultBuffer = Buffer.from('\xe5\xe4\xf6');
const defaultHex = 'c3a5c3a4c3b6';
describe('#bufferToHex', () => {
it('should create a hex string from a Buffer', () => {
const hex = bufferToHex(defaultBuffer);
return expect(hex).to.be.equal(defaultHex);
});
});
describe('#hexToBuffer', () => {
it('should create a Buffer from a hex string', () => {
const buffer = hexToBuffer(defaultHex);
return expect(buffer).to.be.eql(defaultBuffer);
});
it('should throw TypeError with number', () => {
return expect(hexToBuffer.bind(null, 123)).to.throw(
TypeError,
'Argument must be a string.',
);
});
it('should throw TypeError with object', () => {
return expect(hexToBuffer.bind(null, {})).to.throw(
TypeError,
'Argument must be a string.',
);
});
it('should throw an error for a non-string input with custom argument name', () => {
return expect(hexToBuffer.bind(null, {}, 'Custom')).to.throw(
'Custom must be a string.',
);
});
it('should throw TypeError with non hex string', () => {
return expect(hexToBuffer.bind(null, 'yKJj')).to.throw(
TypeError,
'Argument must be a valid hex string.',
);
});
it('should throw TypeError with partially correct hex string', () => {
return expect(hexToBuffer.bind(null, 'Abxzzzz')).to.throw(
TypeError,
'Argument must be a valid hex string.',
);
});
it('should throw TypeError with odd number of string with partially correct hex string', () => {
return expect(hexToBuffer.bind(null, 'Abxzzab')).to.throw(
TypeError,
'Argument must be a valid hex string.',
);
});
it('should throw TypeError with odd number hex string with invalid hex', () => {
return expect(hexToBuffer.bind(null, '123xxxx')).to.throw(
TypeError,
'Argument must be a valid hex string.',
);
});
it('should throw an error for a non-hex string input with custom argument name', () => {
return expect(hexToBuffer.bind(null, 'yKJj', 'Custom')).to.throw(
'Custom must be a valid hex string.',
);
});
it('should throw TypeError with odd-length hex string', () => {
return expect(hexToBuffer.bind(null, 'c3a5c3a4c3b6a')).to.throw(
TypeError,
'Argument must have a valid length of hex string.',
);
});
it('should throw an error for an odd-length hex string input with custom argument name', () => {
return expect(hexToBuffer.bind(null, 'c3a5c3a4c3b6a', 'Custom')).to.throw(
'Custom must have a valid length of hex string.',
);
});
});
describe('#bigNumberToBuffer', () => {
it('should convert a big number to a buffer', () => {
const bigNumber = '58191285901858109';
const addressSize = 8;
const expectedBuffer = Buffer.from('00cebcaa8d34153d', 'hex');
return expect(bigNumberToBuffer(bigNumber, addressSize)).to.be.eql(
expectedBuffer,
);
});
});
describe('#bufferToBigNumberString', () => {
it('should convert a buffer to a big number', () => {
const bigNumber = '58191285901858109';
const buffer = Buffer.from('00cebcaa8d34153d', 'hex');
return expect(bufferToBigNumberString(buffer)).to.be.equal(bigNumber);
});
});
});
================================================
FILE: packages/lisk-cryptography/test/convert.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
getFirstEightBytesReversed,
toAddress,
getAddressFromPublicKey,
convertPublicKeyEd2Curve,
convertPrivateKeyEd2Curve,
stringifyEncryptedPassphrase,
parseEncryptedPassphrase,
} from '../src/convert';
// Require is used for stubbing
const hashModule = require('../src/hash');
describe('convert', () => {
// keys for passphrase 'secret';
const defaultPrivateKey =
'2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultPublicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultPublicKeyHash = Buffer.from(
'3a971fd02b4a07fc20aad1936d3cb1d263b96e0ffd938625e5c0db1ad8ba2a29',
'hex',
);
const defaultPrivateKeyCurve = Buffer.from(
'68b211b2c01cc88690ba76a07895a5b4805e1c11fdd3af4c863e6d4efeb14378',
'hex',
);
const defaultPublicKeyCurve = Buffer.from(
'6f9d780305bda43dd47a291d897f2d8845a06160632d82fb1f209fdd46ed3c1e',
'hex',
);
const defaultAddress = '18160565574430594874L';
const defaultStringWithMoreThanEightCharacters = '0123456789';
const defaultFirstEightCharactersReversed = '76543210';
const defaultDataForBuffer = 'Hello!';
const defaultAddressFromBuffer = '79600447942433L';
describe('#getFirstEightBytesReversed', () => {
it('should get the first eight bytes reversed from a Buffer', () => {
const bufferEntry = Buffer.from(defaultStringWithMoreThanEightCharacters);
const reversedAndCut = getFirstEightBytesReversed(bufferEntry);
return expect(reversedAndCut).to.be.eql(
Buffer.from(defaultFirstEightCharactersReversed),
);
});
it('should get the first eight bytes reversed from a string', () => {
const reversedAndCut = getFirstEightBytesReversed(
defaultStringWithMoreThanEightCharacters,
);
return expect(reversedAndCut).to.be.eql(
Buffer.from(defaultFirstEightCharactersReversed),
);
});
});
describe('#toAddress', () => {
it('should create an address from a buffer', () => {
const bufferInit = Buffer.from(defaultDataForBuffer);
const address = toAddress(bufferInit);
return expect(address).to.be.eql(defaultAddressFromBuffer);
});
it('should throw on more than 8 bytes as input', () => {
const bufferExceedError =
'The buffer for Lisk addresses must not have more than 8 bytes';
const bufferInit = Buffer.from(defaultStringWithMoreThanEightCharacters);
return expect(toAddress.bind(null, bufferInit)).to.throw(
bufferExceedError,
);
});
});
describe('#getAddressFromPublicKey', () => {
beforeEach(() => {
return sandbox.stub(hashModule, 'hash').returns(defaultPublicKeyHash);
});
it('should generate address from publicKey', () => {
const address = getAddressFromPublicKey(defaultPublicKey);
return expect(address).to.be.equal(defaultAddress);
});
});
describe('#convertPublicKeyEd2Curve', () => {
it('should convert publicKey ED25519 to Curve25519 key', () => {
const result = convertPublicKeyEd2Curve(
Buffer.from(defaultPublicKey, 'hex'),
);
expect(result).to.not.be.null;
const curveRepresentation = result as Buffer;
return expect(
defaultPublicKeyCurve.equals(Buffer.from(curveRepresentation)),
).to.be.true;
});
});
describe('#convertPrivateKeyEd2Curve', () => {
it('should convert privateKey ED25519 to Curve25519 key', () => {
const curveRepresentation = convertPrivateKeyEd2Curve(
Buffer.from(defaultPrivateKey, 'hex'),
);
return expect(
defaultPrivateKeyCurve.equals(Buffer.from(curveRepresentation)),
).to.be.true;
});
});
describe('#stringifyEncryptedPassphrase', () => {
it('should throw an error if encrypted passphrase is not an object', () => {
const encryptedPassphrase =
'salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
return expect(
stringifyEncryptedPassphrase.bind(null, encryptedPassphrase),
).to.throw('Encrypted passphrase to stringify must be an object.');
});
it('should format an encrypted passphrase as a string', () => {
const encryptedPassphrase = {
salt: 'e8c7dae4c893e458e0ebb8bff9a36d84',
cipherText:
'c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333',
iv: '1a2206e426c714091b7e48f6',
tag: '3a9d9f9f9a92c9a58296b8df64820c15',
version: '1',
};
const stringifiedEncryptedPassphrase =
'salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
return expect(stringifyEncryptedPassphrase(encryptedPassphrase)).to.equal(
stringifiedEncryptedPassphrase,
);
});
it('should format an encrypted passphrase with custom iterations as a string', () => {
const encryptedPassphrase = {
iterations: 1,
salt: 'e8c7dae4c893e458e0ebb8bff9a36d84',
cipherText:
'c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333',
iv: '1a2206e426c714091b7e48f6',
tag: '3a9d9f9f9a92c9a58296b8df64820c15',
version: '1',
};
const stringifiedEncryptedPassphrase =
'iterations=1&salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
return expect(stringifyEncryptedPassphrase(encryptedPassphrase)).to.equal(
stringifiedEncryptedPassphrase,
);
});
});
describe('#parseEncryptedPassphrase', () => {
it('should throw an error if encrypted passphrase is not a string', () => {
const stringifiedEncryptedPassphrase = { abc: 'def' };
return expect(
parseEncryptedPassphrase.bind(null, stringifiedEncryptedPassphrase),
).to.throw('Encrypted passphrase to parse must be a string.');
});
it('should throw an error if iterations is present but not a valid number', () => {
const stringifiedEncryptedPassphrase =
'iterations=null&salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
return expect(
parseEncryptedPassphrase.bind(null, stringifiedEncryptedPassphrase),
).to.throw('Could not parse iterations.');
});
it('should throw an error if multiple values are in a key', () => {
const stringifiedEncryptedPassphrase =
'salt=xxx&salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
return expect(
parseEncryptedPassphrase.bind(null, stringifiedEncryptedPassphrase),
).to.throw(
'Encrypted passphrase to parse must have only one value per key.',
);
});
it('should parse an encrypted passphrase string', () => {
const stringifiedEncryptedPassphrase =
'salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
const encryptedPassphrase = {
iterations: undefined,
salt: 'e8c7dae4c893e458e0ebb8bff9a36d84',
cipherText:
'c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333',
iv: '1a2206e426c714091b7e48f6',
tag: '3a9d9f9f9a92c9a58296b8df64820c15',
version: '1',
};
return expect(
parseEncryptedPassphrase(stringifiedEncryptedPassphrase),
).to.eql(encryptedPassphrase);
});
it('should parse an encrypted passphrase string with custom iterations', () => {
const stringifiedEncryptedPassphrase =
'iterations=1&salt=e8c7dae4c893e458e0ebb8bff9a36d84&cipherText=c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333&iv=1a2206e426c714091b7e48f6&tag=3a9d9f9f9a92c9a58296b8df64820c15&version=1';
const encryptedPassphrase = {
iterations: 1,
salt: 'e8c7dae4c893e458e0ebb8bff9a36d84',
cipherText:
'c0fab123d83c386ffacef9a171b6e0e0e9d913e58b7972df8e5ef358afbc65f99c9a2b6fe7716f708166ed72f59f007d2f96a91f48f0428dd51d7c9962e0c6a5fc27ca0722038f1f2cf16333',
iv: '1a2206e426c714091b7e48f6',
tag: '3a9d9f9f9a92c9a58296b8df64820c15',
version: '1',
};
return expect(
parseEncryptedPassphrase(stringifiedEncryptedPassphrase),
).to.eql(encryptedPassphrase);
});
});
});
================================================
FILE: packages/lisk-cryptography/test/encrypt.ts
================================================
/** Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as sinon from 'sinon';
import {
EncryptedPassphraseObject,
EncryptedMessageWithNonce,
encryptMessageWithPassphrase,
decryptMessageWithPassphrase,
encryptPassphraseWithPassword,
decryptPassphraseWithPassword,
} from '../src/encrypt';
// Require is used for stubbing
const convert = require('../src/convert');
const keys = require('../src/keys');
const hashModule = require('../src/hash');
describe('encrypt', () => {
const PBKDF2_ITERATIONS = 1e6;
const ENCRYPTION_VERSION = '1';
const defaultPassphrase =
'minute omit local rare sword knee banner pair rib museum shadow juice';
const defaultPrivateKey =
'314852d7afb0d4c283692fef8a2cb40e30c7a5df2ed79994178c10ac168d6d977ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultPublicKey =
'7ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultSecondPassphrase = 'second secret';
const defaultSecondPrivateKey =
'9ef4146f8166d32dc8051d3d9f3a0c4933e24aa8ccb439b5d9ad00078a89e2fc0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
const defaultSecondPublicKey =
'0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
const defaultMessage = 'Some default text.';
const defaultPassword = 'myTotal53cr3t%&';
const customIterations = 12;
let defaultEncryptedMessageWithNonce: EncryptedMessageWithNonce;
let getPrivateAndPublicKeyBytesFromPassphraseStub;
let hashStub: sinon.SinonStub;
beforeEach(() => {
defaultEncryptedMessageWithNonce = {
encryptedMessage:
'299390b9cbb92fe6a43daece2ceaecbacd01c7c03cfdba51d693b5c0e2b65c634115',
nonce: 'df4c8b09e270d2cb3f7b3d53dfa8a6f3441ad3b14a13fb66',
};
sandbox
.stub(convert, 'convertPrivateKeyEd2Curve')
.returns(
Buffer.from(
'd8be8cacb03fb02f34e85030f902b635f364d6c23f090c7640e9dc9c568e7d5e',
'hex',
),
);
sandbox
.stub(convert, 'convertPublicKeyEd2Curve')
.returns(
Buffer.from(
'f245e78c83196d73452e55581ef924a1b792d352c142257aa3af13cded2e7905',
'hex',
),
);
getPrivateAndPublicKeyBytesFromPassphraseStub = sandbox.stub(
keys,
'getPrivateAndPublicKeyBytesFromPassphrase',
);
getPrivateAndPublicKeyBytesFromPassphraseStub
.withArgs(defaultPassphrase)
.returns({
privateKey: Buffer.from(defaultPrivateKey, 'hex'),
publicKey: Buffer.from(defaultPublicKey, 'hex'),
});
getPrivateAndPublicKeyBytesFromPassphraseStub
.withArgs(defaultSecondPassphrase)
.returns({
privateKey: Buffer.from(defaultSecondPrivateKey, 'hex'),
publicKey: Buffer.from(defaultSecondPublicKey, 'hex'),
});
hashStub = sandbox
.stub(hashModule, 'hash')
.returns(
Buffer.from(
'd43eed9049dd8f35106c720669a1148b2c6288d9ea517b936c33a1d84117a760',
'hex',
),
);
return Promise.resolve();
});
describe('#encryptMessageWithPassphrase', () => {
let encryptedMessage: EncryptedMessageWithNonce;
beforeEach(() => {
encryptedMessage = encryptMessageWithPassphrase(
defaultMessage,
defaultPassphrase,
defaultPublicKey,
);
return Promise.resolve();
});
it('should encrypt a message', () => {
return expect(encryptedMessage)
.to.have.property('encryptedMessage')
.be.hexString.with.length(68);
});
it('should output the nonce', () => {
return expect(encryptedMessage)
.to.have.property('nonce')
.be.hexString.with.length(48);
});
});
describe('#decryptMessageWithPassphrase', () => {
it('should be able to decrypt the message correctly using the receiver’s secret passphrase', () => {
const decryptedMessage = decryptMessageWithPassphrase(
defaultEncryptedMessageWithNonce.encryptedMessage,
defaultEncryptedMessageWithNonce.nonce,
defaultPassphrase,
defaultPublicKey,
);
return expect(decryptedMessage).to.be.equal(defaultMessage);
});
it('should inform the user if the nonce is the wrong length', () => {
return expect(
decryptMessageWithPassphrase.bind(
null,
defaultEncryptedMessageWithNonce.encryptedMessage,
defaultEncryptedMessageWithNonce.encryptedMessage.slice(0, 2),
defaultPassphrase,
defaultPublicKey,
),
).to.throw('Expected nonce to be 24 bytes.');
});
it('should inform the user if something goes wrong during decryption', () => {
return expect(
decryptMessageWithPassphrase.bind(
null,
defaultEncryptedMessageWithNonce.encryptedMessage.slice(0, 2),
defaultEncryptedMessageWithNonce.nonce,
defaultSecondPassphrase,
defaultPublicKey,
),
).to.throw(
'Something went wrong during decryption. Is this the full encrypted message?',
);
});
});
describe('encrypt and decrypt passphrase with password', () => {
beforeEach(() => {
return hashStub.returns(
Buffer.from(
'e09dfc943d65d63f4f31e444c81afc6d5cf442c988fb87180165dd7119d3ae61',
'hex',
),
);
});
describe('#encryptPassphraseWithPassword', () => {
let startTime: number;
let encryptedPassphrase: EncryptedPassphraseObject;
beforeEach(() => {
startTime = Date.now();
encryptedPassphrase = encryptPassphraseWithPassword(
defaultPassphrase,
defaultPassword,
);
return Promise.resolve();
});
it('should encrypt a passphrase', () => {
return expect(encryptedPassphrase).to.have.property('cipherText').and.be
.hexString;
});
it('should output the IV', () => {
return expect(encryptedPassphrase)
.to.have.property('iv')
.and.be.hexString.and.have.length(24);
});
it('should output the salt', () => {
return expect(encryptedPassphrase)
.to.have.property('salt')
.and.be.hexString.and.have.length(32);
});
it('should output the tag', () => {
return expect(encryptedPassphrase)
.to.have.property('tag')
.and.be.hexString.and.have.length(32);
});
it('should output the current version of Lisk Elements', () => {
return expect(encryptedPassphrase)
.to.have.property('version')
.which.is.equal(ENCRYPTION_VERSION);
});
it('should output the default number of iterations', () => {
return expect(encryptedPassphrase)
.to.have.property('iterations')
.equal(PBKDF2_ITERATIONS);
});
it('should take more than 0.5 seconds @node-only', () => {
const endTime = Date.now();
return expect(endTime - startTime).to.be.above(500);
});
it('should take less than 2 seconds @node-only', () => {
const endTime = Date.now();
return expect(endTime - startTime).to.be.below(2e3);
});
it('should accept and output a custom number of iterations', () => {
const encryptedPassphraseWithIterations = encryptPassphraseWithPassword(
defaultPassphrase,
defaultPassword,
customIterations,
);
return expect(encryptedPassphraseWithIterations)
.to.have.property('iterations')
.and.equal(customIterations);
});
});
describe('#decryptPassphraseWithPassword', () => {
let encryptedPassphrase = {
iterations: undefined,
cipherText:
'5cfd7bcc13022a482e7c8bd250cd73ef3eb7c49c849d5e761ce717608293f777cca8e0e18587ee307beab65bcc1b273caeb23d4985010b675391b354c38f8e84e342c1e7aa',
iv: '7b820ad6936a63152d13ffa2',
salt: 'b60036ab30da7af68c6ecf370471ce1b',
tag: '336c68fa92d414c229e5638249847774',
version: '1',
};
it('should decrypt a passphrase with a password', () => {
const decrypted = decryptPassphraseWithPassword(
encryptedPassphrase,
defaultPassword,
);
return expect(decrypted).to.be.equal(defaultPassphrase);
});
it('should inform the user if cipherText is missing', () => {
const {
cipherText,
...encryptedPassphraseWithoutCipherText
} = encryptedPassphrase;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithoutCipherText,
defaultPassword,
),
).to.throw('Cipher text must be a string.');
});
it('should inform the user if iv is missing', () => {
const { iv, ...encryptedPassphraseWithoutIv } = encryptedPassphrase;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithoutIv,
defaultPassword,
),
).to.throw('IV must be a string.');
});
it('should inform the user if salt is missing', () => {
const { salt, ...encryptedPassphraseWithoutSalt } = encryptedPassphrase;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithoutSalt,
defaultPassword,
),
).to.throw('Salt must be a string.');
});
it('should inform the user if tag is missing', () => {
const { tag, ...encryptedPassphraseWithoutTag } = encryptedPassphrase;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithoutTag,
defaultPassword,
),
).to.throw('Tag must be a string.');
});
it('should inform the user if the salt has been altered', () => {
const { salt, ...encryptedPassphraseWithoutSalt } = encryptedPassphrase;
const encryptedPassphraseWithAlteredSalt = {
salt: `00${encryptedPassphrase.salt.slice(2)}`,
...encryptedPassphraseWithoutSalt,
};
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithAlteredSalt,
defaultPassword,
),
).to.throw('Unsupported state or unable to authenticate data');
});
it('should inform the user if the tag has been shortened', () => {
const { tag, ...encryptedPassphraseWithoutTag } = encryptedPassphrase;
const encryptedPassphraseWithAlteredTag = {
tag: encryptedPassphrase.tag.slice(0, 30),
...encryptedPassphraseWithoutTag,
};
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithAlteredTag,
defaultPassword,
),
).to.throw('Tag must be 16 bytes.');
});
it('should inform the user if the tag is not a hex string', () => {
const { tag, ...encryptedPassphraseWithoutTag } = encryptedPassphrase;
const encryptedPassphraseWithAlteredTag = {
tag: `${encryptedPassphrase.tag.slice(0, 30)}gg`,
...encryptedPassphraseWithoutTag,
};
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithAlteredTag,
defaultPassword,
),
).to.throw('Tag must be a valid hex string.');
});
it('should inform the user if the tag has been altered', () => {
const { tag, ...encryptedPassphraseWithoutTag } = encryptedPassphrase;
const encryptedPassphraseWithAlteredTag = {
tag: `00${encryptedPassphrase.tag.slice(2)}`,
...encryptedPassphraseWithoutTag,
};
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphraseWithAlteredTag,
defaultPassword,
),
).to.throw('Unsupported state or unable to authenticate data');
});
it('should decrypt a passphrase with a password and a custom number of iterations', () => {
const encryptedPassphraseWithCustomIterations = {
iterations: 12,
cipherText:
'1f06671e13c0329aee057fee995e08a516bdacd287c7ff2714a74be6099713c87bbc3e005c63d4d3d02f8ba89b42810a5854444ad2b76855007a0925fafa7d870875beb010',
iv: '3a583b21bbac609c7df3e7e0',
salt: '245c6859a96339a7735a6cac78ccf625',
tag: '63653f1d4e8d422a42d98b25d3844792',
version: '1',
};
const decrypted = decryptPassphraseWithPassword(
encryptedPassphraseWithCustomIterations,
defaultPassword,
);
return expect(decrypted).to.be.equal(defaultPassphrase);
});
});
describe('integration test', () => {
it('should encrypt a given passphrase with a password and decrypt it back to the original passphrase @node-only', () => {
const encryptedPassphrase = encryptPassphraseWithPassword(
defaultPassphrase,
defaultPassword,
);
const decryptedString = decryptPassphraseWithPassword(
encryptedPassphrase,
defaultPassword,
);
return expect(decryptedString).to.be.equal(defaultPassphrase);
}).timeout(5000);
it('should encrypt a given passphrase with a password and custom number of iterations and decrypt it back to the original passphrase @node-only', () => {
const encryptedPassphrase = encryptPassphraseWithPassword(
defaultPassphrase,
defaultPassword,
customIterations,
);
const decryptedString = decryptPassphraseWithPassword(
encryptedPassphrase,
defaultPassword,
);
return expect(decryptedString).to.equal(defaultPassphrase);
});
});
});
});
================================================
FILE: packages/lisk-cryptography/test/hash.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { hash as hashFunction } from '../src/hash';
import { expect } from 'chai';
describe('hash', () => {
const defaultText = 'text123*';
let arrayToHash: ReadonlyArray;
let defaultHash: Buffer;
beforeEach(() => {
defaultHash = Buffer.from(
'7607d6792843d6003c12495b54e34517a508d2a8622526aff1884422c5478971',
'hex',
);
arrayToHash = [1, 2, 3];
return Promise.resolve();
});
it('should generate a sha256 hash from a Buffer', () => {
const testBuffer = Buffer.from(defaultText);
const hash = hashFunction(testBuffer);
return expect(hash).to.be.eql(defaultHash);
});
it('should generate a sha256 hash from a utf8 string', () => {
const hash = hashFunction(defaultText, 'utf8');
return expect(hash).to.be.eql(defaultHash);
});
it('should generate a sha256 hash from a hex string', () => {
const testHex = Buffer.from(defaultText).toString('hex');
const hash = hashFunction(testHex, 'hex');
return expect(hash).to.be.eql(defaultHash);
});
it('should throw on unknown format when trying a string with format "utf32"', () => {
return expect(hashFunction.bind(null, defaultText, 'utf32')).to.throw(
'Unsupported string format. Currently only `hex` and `utf8` are supported.',
);
});
it('should throw on unknown format when using an array', () => {
return expect(hashFunction.bind(null, arrayToHash)).to.throw(
'Unsupported data format. Currently only Buffers or `hex` and `utf8` strings are supported.',
);
});
});
================================================
FILE: packages/lisk-cryptography/test/helpers/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export const makeInvalid = (str: string): string => {
const char = str[0] === '0' ? '1' : '0';
return `${char}${str.slice(1)}`;
};
================================================
FILE: packages/lisk-cryptography/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '../src';
import { expect } from 'chai';
describe('cryptography index.js', () => {
it('should export an object', () => {
return expect(cryptography).to.be.an('object');
});
});
================================================
FILE: packages/lisk-cryptography/test/keys.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
Keypair,
KeypairBytes,
getPrivateAndPublicKeyFromPassphrase,
getPrivateAndPublicKeyBytesFromPassphrase,
getKeys,
getAddressAndPublicKeyFromPassphrase,
getAddressFromPassphrase,
} from '../src/keys';
// Require is used for stubbing
const buffer = require('../src/buffer');
const hashModule = require('../src/hash');
describe('keys', () => {
const defaultPassphrase = 'secret';
const defaultPassphraseHash =
'2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b';
const defaultPrivateKey =
'2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultPublicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultAddress = '16402986683325069355L';
const defaultAddressAndPublicKey = {
publicKey: defaultPublicKey,
address: defaultAddress,
};
let bufferToHexStub;
beforeEach(() => {
bufferToHexStub = sandbox.stub(buffer, 'bufferToHex');
bufferToHexStub
.withArgs(Buffer.from(defaultPrivateKey, 'hex'))
.returns(defaultPrivateKey);
bufferToHexStub
.withArgs(Buffer.from(defaultPublicKey, 'hex'))
.returns(defaultPublicKey);
return sandbox
.stub(hashModule, 'hash')
.returns(Buffer.from(defaultPassphraseHash, 'hex'));
});
describe('#getPrivateAndPublicKeyBytesFromPassphrase', () => {
let keyPair: KeypairBytes;
beforeEach(() => {
keyPair = getPrivateAndPublicKeyBytesFromPassphrase(defaultPassphrase);
return Promise.resolve();
});
it('should create buffer publicKey', () => {
return expect(
Buffer.from(keyPair.publicKeyBytes).toString('hex'),
).to.be.equal(defaultPublicKey);
});
it('should create buffer privateKey', () => {
return expect(
Buffer.from(keyPair.privateKeyBytes).toString('hex'),
).to.be.equal(defaultPrivateKey);
});
});
describe('#getPrivateAndPublicKeyFromPassphrase', () => {
let keyPair: Keypair;
beforeEach(() => {
keyPair = getPrivateAndPublicKeyFromPassphrase(defaultPassphrase);
return Promise.resolve();
});
it('should generate the correct publicKey from a passphrase', () => {
return expect(keyPair)
.to.have.property('publicKey')
.and.be.equal(defaultPublicKey);
});
it('should generate the correct privateKey from a passphrase', () => {
return expect(keyPair)
.to.have.property('privateKey')
.and.be.equal(defaultPrivateKey);
});
});
describe('#getKeys', () => {
let keyPair: Keypair;
beforeEach(() => {
keyPair = getKeys(defaultPassphrase);
return Promise.resolve();
});
it('should generate the correct publicKey from a passphrase', () => {
return expect(keyPair)
.to.have.property('publicKey')
.and.be.equal(defaultPublicKey);
});
it('should generate the correct privateKey from a passphrase', () => {
return expect(keyPair)
.to.have.property('privateKey')
.and.be.equal(defaultPrivateKey);
});
});
describe('#getAddressAndPublicKeyFromPassphrase', () => {
it('should create correct address and publicKey', () => {
return expect(
getAddressAndPublicKeyFromPassphrase(defaultPassphrase),
).to.eql(defaultAddressAndPublicKey);
});
});
describe('#getAddressFromPassphrase', () => {
it('should create correct address', () => {
return expect(getAddressFromPassphrase(defaultPassphrase)).to.equal(
defaultAddress,
);
});
});
});
================================================
FILE: packages/lisk-cryptography/test/mocha.opts
================================================
--recursive
--require ts-node/register
--require tsconfig-paths/register
--require source-map-support/register
--require ./test/_setup.ts
--file ./test/_global_hooks.ts
--watch-extensions ts
================================================
FILE: packages/lisk-cryptography/test/nacl/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { NaclInterface } from '../../src/nacl/nacl_types';
import * as fast from '../../src/nacl/fast';
import * as slow from '../../src/nacl/slow';
// Require is used for stubbing
const moduleLibrary = require('module');
const resetTest = () => {
// Reset environment variable
delete process.env.NACL_FAST;
// Delete require cache to force it to re-load module
delete require.cache[require.resolve('../../src/nacl')];
};
interface naclLibrary extends NaclInterface {
NACL_SIGN_PUBLICKEY_LENGTH: number;
NACL_SIGN_SIGNATURE_LENGTH: number;
}
const stripConstants = (library: naclLibrary) => {
// Constants are added in ../../src/nacl/index.js
const {
NACL_SIGN_PUBLICKEY_LENGTH,
NACL_SIGN_SIGNATURE_LENGTH,
...strippedLib
} = library;
return strippedLib;
};
describe('nacl index.js', () => {
let initialEnvVar: string | undefined;
before(() => {
initialEnvVar = process.env.NACL_FAST;
return Promise.resolve();
});
after(() => {
if (initialEnvVar) {
process.env.NACL_FAST = initialEnvVar;
} else {
delete process.env.NACL_FAST;
}
return Promise.resolve();
});
beforeEach(() => {
resetTest();
return Promise.resolve();
});
describe('nacl fast installed', () => {
beforeEach(() => {
resetTest();
return Promise.resolve();
});
it('should load nacl fast if process.env.NACL_FAST is set to enable', () => {
process.env.NACL_FAST = 'enable';
const loadedLibrary = require('../../src/nacl');
const strippedLibrary = stripConstants(loadedLibrary);
return expect(strippedLibrary).to.be.eql(fast);
});
it('should load nacl slow if process.env.NACL_FAST is set to disable', () => {
process.env.NACL_FAST = 'disable';
const loadedLibrary = require('../../src/nacl');
const strippedLibrary = stripConstants(loadedLibrary);
return expect(strippedLibrary).to.be.eql(slow);
});
it('should load nacl fast if process.env.NACL_FAST is undefined', () => {
process.env.NACL_FAST = undefined;
const loadedLibrary = require('../../src/nacl');
const strippedLibrary = stripConstants(loadedLibrary);
return expect(strippedLibrary).to.be.eql(fast);
});
});
describe('nacl fast not installed', () => {
const moduleNotFoundError = new Error('MODULE_NOT_FOUND');
beforeEach(() => {
resetTest();
// "require" is a wrapper around Module._load which handles the actual loading
sandbox
.stub(moduleLibrary, '_load')
.callThrough()
.withArgs('./fast')
.throws(moduleNotFoundError);
return Promise.resolve();
});
it('should set process.env.NACL_FAST to disable', () => {
require('../../src/nacl');
return expect(process.env.NACL_FAST).to.eql('disable');
});
it('should load nacl slow if process.env.NACL_FAST is set to enable', () => {
process.env.NACL_FAST = 'enable';
const loadedLibrary = require('../../src/nacl');
const strippedLibrary = stripConstants(loadedLibrary);
return expect(strippedLibrary).to.eql(slow);
});
it('should load nacl slow if process.env.NACL_FAST is set to disable', () => {
process.env.NACL_FAST = 'disable';
const loadedLibrary = require('../../src/nacl');
const strippedLibrary = stripConstants(loadedLibrary);
return expect(strippedLibrary).to.eql(slow);
});
it('should load nacl slow if process.env.NACL_FAST is undefined', () => {
process.env.NACL_FAST = undefined;
const loadedLibrary = require('../../src/nacl');
const strippedLibrary = stripConstants(loadedLibrary);
return expect(strippedLibrary).to.eql(slow);
});
});
});
================================================
FILE: packages/lisk-cryptography/test/nacl/nacl.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { KeypairBytes } from '../../src/keys';
import { makeInvalid } from '../helpers';
import { NaclInterface } from '../../src/nacl/nacl_types';
import * as fast from '../../src/nacl/fast';
import * as slow from '../../src/nacl/slow';
describe('nacl', () => {
const defaultPublicKey =
'7ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultPrivateKey =
'314852d7afb0d4c283692fef8a2cb40e30c7a5df2ed79994178c10ac168d6d977ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultMessage = 'Some default text.';
const defaultSignature =
'68937004b6720d7e1902ef05a577e6d9f9ab2756286b1f2ae918f8a0e5153c15e4f410916076f750b708f8979be2430e4cfc7ebb523ae1905d2ea1f5d24ce700';
const defaultEncryptedMessage =
'a232e5ea10e18249efc5a0aa8ed68271fc494d02245c52277ee2e14cddd960144a65';
const defaultNonce = 'df4c8b09e270d2cb3f7b3d53dfa8a6f3441ad3b14a13fb66';
const defaultHash =
'314852d7afb0d4c283692fef8a2cb40e30c7a5df2ed79994178c10ac168d6d97';
const defaultDigest =
'aba8462bb7a1460f1e36c36a71f0b7f67d1606562001907c1b2dad08a8ce74ae';
const defaultConvertedPublicKeyEd2Curve =
'b8c0eecfd16c1cc4f057a6fc6d8dd3d46e4aa9625408d4bd0ba00e991326fe00';
const defaultConvertedPrivateKeyEd2Curve =
'b0e3276b64b086b381e11928e56f966d062dc677b7801cc594aeb2d4193e8d57';
const libraries = [
{
name: 'fast',
library: fast,
},
{
name: 'slow',
library: slow,
},
];
interface library {
name: string;
library: NaclInterface;
}
libraries.forEach((nacl: library) => {
describe(`${nacl.name}`, () => {
const {
box,
getRandomBytes,
getKeyPair,
openBox,
signDetached,
verifyDetached,
}: NaclInterface = nacl.library;
describe('#getRandomBytes', () => {
const size = 24;
let randomBuffer: Buffer;
beforeEach(() => {
randomBuffer = getRandomBytes(size);
return Promise.resolve();
});
it('should return an uint8array', () => {
return expect(randomBuffer).to.be.instanceOf(Uint8Array);
});
it('should return an uint8array of size 24', () => {
return expect(randomBuffer.length).to.be.eql(24);
});
});
describe('#getKeyPair', () => {
let signedKeys: KeypairBytes;
beforeEach(() => {
signedKeys = getKeyPair(Buffer.from(defaultHash, 'hex'));
return Promise.resolve();
});
it('should create a publicKey', () => {
return expect(
Buffer.from(signedKeys.publicKeyBytes).toString('hex'),
).to.be.eql(defaultPublicKey);
});
it('should create a publicKey of type uint8array', () => {
return expect(signedKeys.publicKeyBytes).to.be.instanceOf(Uint8Array);
});
it('should create a privateKey', () => {
return expect(
Buffer.from(signedKeys.privateKeyBytes).toString('hex'),
).to.be.eql(defaultPrivateKey);
});
it('should create a privateKey of type uint8array', () => {
return expect(signedKeys.privateKeyBytes).to.be.instanceOf(
Uint8Array,
);
});
});
describe('#signDetached', () => {
let signatureBytes: Buffer;
beforeEach(() => {
signatureBytes = signDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultPrivateKey, 'hex'),
);
return Promise.resolve();
});
it('should create a signature', () => {
return expect(Buffer.from(signatureBytes).toString('hex')).to.be.eql(
defaultSignature,
);
});
it('should create a signature of type uint8array', () => {
return expect(signatureBytes).to.be.instanceOf(Uint8Array);
});
});
describe('#verifyDetached', () => {
it('should return false if the signature is invalid', () => {
const verification = verifyDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(makeInvalid(defaultSignature), 'hex'),
Buffer.from(defaultPublicKey, 'hex'),
);
return expect(verification).to.be.false;
});
it('should return true if the signature is valid', () => {
const verification = verifyDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultSignature, 'hex'),
Buffer.from(defaultPublicKey, 'hex'),
);
return expect(verification).to.be.true;
});
});
describe('#box', () => {
let encryptedMessageBytes: Buffer;
beforeEach(() => {
encryptedMessageBytes = box(
Buffer.from(defaultMessage, 'utf8'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
return Promise.resolve();
});
it('should encrypt a message', () => {
return expect(
Buffer.from(encryptedMessageBytes).toString('hex'),
).to.be.eql(defaultEncryptedMessage);
});
});
describe('#openBox', () => {
let decryptedMessageBytes: Buffer;
beforeEach(() => {
decryptedMessageBytes = openBox(
Buffer.from(defaultEncryptedMessage, 'hex'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
return Promise.resolve();
});
it('should decrypt a message', () => {
return expect(
Buffer.from(decryptedMessageBytes).toString('utf8'),
).to.be.eql(defaultMessage);
});
it('should throw an error for an invalid message', () => {
return expect(
openBox.bind(
null,
Buffer.from(
'abcdef1234567890abcdef1234567890abcdef1234567890',
'hex',
),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
),
).to.throw(Error, 'Failed to decrypt message');
});
});
describe('integration tests', () => {
it('should encrypt a given message with a nonce and converted key pair, and decrypt it back to the original message', () => {
const encryptedMessageBytes = box(
Buffer.from(defaultMessage, 'utf8'),
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
const decryptedMessageBytes = openBox(
encryptedMessageBytes,
Buffer.from(defaultNonce, 'hex'),
Buffer.from(defaultConvertedPublicKeyEd2Curve, 'hex'),
Buffer.from(defaultConvertedPrivateKeyEd2Curve, 'hex'),
);
return expect(
Buffer.from(decryptedMessageBytes).toString('utf8'),
).to.equal(defaultMessage);
});
it('should sign a given message and verify it using the same signature', () => {
const signatureBytes = signDetached(
Buffer.from(defaultDigest, 'hex'),
Buffer.from(defaultPrivateKey, 'hex'),
);
const verification = verifyDetached(
Buffer.from(defaultDigest, 'hex'),
signatureBytes,
Buffer.from(defaultPublicKey, 'hex'),
);
return expect(verification).to.be.true;
});
});
});
});
});
================================================
FILE: packages/lisk-cryptography/test/sign.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { makeInvalid } from './helpers';
import {
SignedMessageWithOnePassphrase,
SignedMessageWithTwoPassphrases,
signMessageWithPassphrase,
signMessageWithTwoPassphrases,
verifyMessageWithPublicKey,
verifyMessageWithTwoPublicKeys,
printSignedMessage,
signAndPrintMessage,
signData,
signDataWithPassphrase,
signDataWithPrivateKey,
verifyData,
digestMessage,
} from '../src/sign';
// Require is used for stubbing
const keys = require('../src/keys');
const changeLength = (str: string): string => `00${str}`;
describe('sign', () => {
const defaultPassphrase =
'minute omit local rare sword knee banner pair rib museum shadow juice';
const defaultPrivateKey =
'314852d7afb0d4c283692fef8a2cb40e30c7a5df2ed79994178c10ac168d6d977ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultPublicKey =
'7ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultSecondPassphrase = 'second secret';
const defaultSecondPrivateKey =
'9ef4146f8166d32dc8051d3d9f3a0c4933e24aa8ccb439b5d9ad00078a89e2fc0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
const defaultSecondPublicKey =
'0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
const defaultMessage = 'Some default text.';
const defaultSignature =
'68937004b6720d7e1902ef05a577e6d9f9ab2756286b1f2ae918f8a0e5153c15e4f410916076f750b708f8979be2430e4cfc7ebb523ae1905d2ea1f5d24ce700';
const defaultSecondSignature =
'58013cd8dbc4c194cedb5bdc27232f9de225d077b4dfe817ba810189486bd43e8600e0e8295623882e9db0ba5685bd30e7b7c81f38bc1b668fd9e2370ab9d905';
const defaultPrintedMessage = `
-----BEGIN LISK SIGNED MESSAGE-----
-----MESSAGE-----
${defaultMessage}
-----PUBLIC KEY-----
${defaultPublicKey}
-----SIGNATURE-----
${defaultSignature}
-----END LISK SIGNED MESSAGE-----
`.trim();
const defaultSecondSignedPrintedMessage = `
-----BEGIN LISK SIGNED MESSAGE-----
-----MESSAGE-----
${defaultMessage}
-----PUBLIC KEY-----
${defaultPublicKey}
-----SECOND PUBLIC KEY-----
${defaultSecondPublicKey}
-----SIGNATURE-----
${defaultSignature}
-----SECOND SIGNATURE-----
${defaultSecondSignature}
-----END LISK SIGNED MESSAGE-----
`.trim();
const defaultData = Buffer.from('This is some data');
const defaultDataSignature =
'b8704e11c4d9fad9960c7b6a69dcf48c1bede5b74ed8974cd005d9a407deef618dd800fe69ceed1fd52bb1e0881e71aec137c35b90eda9afe93716a5652ee009';
let defaultSignedMessage: SignedMessageWithOnePassphrase;
let defaultDoubleSignedMessage: SignedMessageWithTwoPassphrases;
let getPrivateAndPublicKeyBytesFromPassphraseStub;
beforeEach(() => {
defaultSignedMessage = {
message: defaultMessage,
publicKey: defaultPublicKey,
signature: defaultSignature,
};
defaultDoubleSignedMessage = {
message: defaultMessage,
publicKey: defaultPublicKey,
secondPublicKey: defaultSecondPublicKey,
signature: defaultSignature,
secondSignature: defaultSecondSignature,
};
getPrivateAndPublicKeyBytesFromPassphraseStub = sandbox.stub(
keys,
'getPrivateAndPublicKeyBytesFromPassphrase',
);
getPrivateAndPublicKeyBytesFromPassphraseStub
.withArgs(defaultPassphrase)
.returns({
privateKeyBytes: Buffer.from(defaultPrivateKey, 'hex'),
publicKeyBytes: Buffer.from(defaultPublicKey, 'hex'),
});
return getPrivateAndPublicKeyBytesFromPassphraseStub
.withArgs(defaultSecondPassphrase)
.returns({
privateKeyBytes: Buffer.from(defaultSecondPrivateKey, 'hex'),
publicKeyBytes: Buffer.from(defaultSecondPublicKey, 'hex'),
});
});
describe('#digestMessage', () => {
const strGenerator = (len: number, chr: string): string => chr.repeat(len);
it('should create message digest for message with length = 0', () => {
const msgBytes = digestMessage('');
const expectedMessageBytes = Buffer.from(
'3fdb82ac2a879b647f4f27f3fbd1c27e0d4e278f830b76295604035330163b79',
'hex',
);
return expect(msgBytes).to.be.eql(expectedMessageBytes);
});
it('should create message digest for message in length range 1 - 253', () => {
const msgBytes = digestMessage(strGenerator(250, 'a'));
const expectedMessageBytes = Buffer.from(
'12832c687d950513aa5db6198b84809eb8fd7ff1c8963dca48ea57278523ec67',
'hex',
);
return expect(msgBytes).to.be.eql(expectedMessageBytes);
});
it('should create message digest for message in length range 254 - 65536', () => {
const msgBytes = digestMessage(strGenerator(65535, 'a'));
const expectedMessageBytes = Buffer.from(
'73da94220312e71eb5c55c94fdddca3c06a6c18cb74a4a4a2cee1a82875c2450',
'hex',
);
return expect(msgBytes).to.be.eql(expectedMessageBytes);
});
it('should create message digest for message in length range 65537 - 4294967296', () => {
const msgBytes = digestMessage(strGenerator(6710886, 'a'));
const expectedMessageBytes = Buffer.from(
'7c51817b5c31c4d04e9ffcf2e78859d6522b124f218c789a8f721b5f3e6b295d',
'hex',
);
return expect(msgBytes).to.be.eql(expectedMessageBytes);
});
// higest range (length > 4294967296) is not practical to test
// but it is covered by `varuint-bitcoin` library
});
describe('#signMessageWithPassphrase', () => {
it('should create a signed message using a secret passphrase', () => {
const signedMessage = signMessageWithPassphrase(
defaultMessage,
defaultPassphrase,
);
return expect(signedMessage).to.be.eql(defaultSignedMessage);
});
});
describe('#verifyMessageWithPublicKey', () => {
it('should detect invalid publicKeys', () => {
return expect(
verifyMessageWithPublicKey.bind(null, {
message: defaultMessage,
signature: defaultSignature,
publicKey: changeLength(defaultPublicKey),
}),
).to.throw('Invalid publicKey, expected 32-byte publicKey');
});
it('should detect invalid signatures', () => {
return expect(
verifyMessageWithPublicKey.bind(null, {
message: defaultMessage,
signature: changeLength(defaultSignature),
publicKey: defaultPublicKey,
}),
).to.throw('Invalid signature length, expected 64-byte signature');
});
it('should return false if the signature is invalid', () => {
const verification = verifyMessageWithPublicKey({
message: defaultMessage,
signature: makeInvalid(defaultSignature),
publicKey: defaultPublicKey,
});
return expect(verification).to.be.false;
});
it('should return true if the signature is valid', () => {
const verification = verifyMessageWithPublicKey(defaultSignedMessage);
return expect(verification).to.be.true;
});
});
describe('#signMessageWithTwoPassphrases', () => {
it('should create a message signed by two secret passphrases', () => {
const signature = signMessageWithTwoPassphrases(
defaultMessage,
defaultPassphrase,
defaultSecondPassphrase,
);
return expect(signature).to.be.eql(defaultDoubleSignedMessage);
});
});
describe('#verifyMessageWithTwoPublicKeys', () => {
it('should throw on invalid first publicKey length', () => {
const {
publicKey,
...messageWithoutPublicKey
} = defaultDoubleSignedMessage;
return expect(
verifyMessageWithTwoPublicKeys.bind(null, {
publicKey: changeLength(defaultPublicKey),
...messageWithoutPublicKey,
}),
).to.throw('Invalid first publicKey, expected 32-byte publicKey');
});
it('should throw on invalid second publicKey length', () => {
const {
secondPublicKey,
...messageWithoutSecondPublicKey
} = defaultDoubleSignedMessage;
return expect(
verifyMessageWithTwoPublicKeys.bind(null, {
secondPublicKey: changeLength(defaultSecondPublicKey),
...messageWithoutSecondPublicKey,
}),
).to.throw('Invalid second publicKey, expected 32-byte publicKey');
});
it('should throw on invalid primary signature length', () => {
const {
signature,
...messageWithoutSignature
} = defaultDoubleSignedMessage;
return expect(
verifyMessageWithTwoPublicKeys.bind(null, {
signature: changeLength(defaultSignature),
...messageWithoutSignature,
}),
).to.throw('Invalid first signature length, expected 64-byte signature');
});
it('should throw on invalid secondary signature length', () => {
const {
secondSignature,
...messageWithoutSecondSignature
} = defaultDoubleSignedMessage;
return expect(
verifyMessageWithTwoPublicKeys.bind(null, {
secondSignature: changeLength(defaultSecondSignature),
...messageWithoutSecondSignature,
}),
).to.throw('Invalid second signature length, expected 64-byte signature');
});
it('should return false for incorrect first signature', () => {
const {
signature,
...messageWithoutSignature
} = defaultDoubleSignedMessage;
const verified = verifyMessageWithTwoPublicKeys({
signature: makeInvalid(defaultSignature),
...messageWithoutSignature,
});
return expect(verified).to.be.false;
});
it('should return false for incorrect second signature', () => {
const {
secondSignature,
...messageWithoutSecondSignature
} = defaultDoubleSignedMessage;
const verified = verifyMessageWithTwoPublicKeys({
secondSignature: makeInvalid(defaultSecondSignature),
...messageWithoutSecondSignature,
});
return expect(verified).to.be.false;
});
it('should return true for two valid signatures', () => {
const verified = verifyMessageWithTwoPublicKeys(
defaultDoubleSignedMessage,
);
return expect(verified).to.be.true;
});
});
describe('#printSignedMessage', () => {
it('should wrap a single signed message into a printed Lisk template', () => {
const printedMessage = printSignedMessage({
message: defaultMessage,
signature: defaultSignature,
publicKey: defaultPublicKey,
});
return expect(printedMessage).to.be.equal(defaultPrintedMessage);
});
it('should wrap a second signed message into a printed Lisk template', () => {
const printedMessage = printSignedMessage({
message: defaultMessage,
signature: defaultSignature,
publicKey: defaultPublicKey,
secondSignature: defaultSecondSignature,
secondPublicKey: defaultSecondPublicKey,
});
return expect(printedMessage).to.be.equal(
defaultSecondSignedPrintedMessage,
);
});
});
describe('#signAndPrintMessage', () => {
it('should sign the message once and wrap it into a printed Lisk template', () => {
const signedAndPrintedMessage = signAndPrintMessage(
defaultMessage,
defaultPassphrase,
);
return expect(signedAndPrintedMessage).to.be.equal(defaultPrintedMessage);
});
it('should sign the message twice and wrap it into a printed Lisk template', () => {
const signedAndPrintedMessage = signAndPrintMessage(
defaultMessage,
defaultPassphrase,
defaultSecondPassphrase,
);
return expect(signedAndPrintedMessage).to.be.equal(
defaultSecondSignedPrintedMessage,
);
});
});
describe('#signData', () => {
let signature: string;
beforeEach(() => {
signature = signData(defaultData, defaultPassphrase);
return Promise.resolve();
});
it('should sign a transaction', () => {
return expect(signature).to.be.equal(defaultDataSignature);
});
});
describe('#signDataWithPassphrase', () => {
let signature: string;
beforeEach(() => {
signature = signDataWithPassphrase(defaultData, defaultPassphrase);
return Promise.resolve();
});
it('should sign a transaction', () => {
return expect(signature).to.be.equal(defaultDataSignature);
});
});
describe('#signDataWithPrivateKey', () => {
let signature: string;
beforeEach(() => {
signature = signDataWithPrivateKey(
defaultData,
Buffer.from(defaultPrivateKey, 'hex'),
);
return Promise.resolve();
});
it('should sign a transaction', () => {
return expect(signature).to.be.equal(defaultDataSignature);
});
});
describe('#verifyData', () => {
it('should return false for an invalid signature', () => {
const verification = verifyData(
defaultData,
makeInvalid(defaultDataSignature),
defaultPublicKey,
);
return expect(verification).to.be.false;
});
it('should return true for a valid signature', () => {
const verification = verifyData(
defaultData,
defaultDataSignature,
defaultPublicKey,
);
return expect(verification).to.be.true;
});
});
});
================================================
FILE: packages/lisk-cryptography/test/tsconfig.json
================================================
{
"extends": "../tsconfig",
"compilerOptions": {
"baseUrl": ".",
"declaration": false,
"target": "es2017",
"typeRoots": ["../types", "../../../types", "../node_modules/@types"]
},
"include": ["../../../types/**/*", "./**/*"]
}
================================================
FILE: packages/lisk-cryptography/types/browserify-bignum/index.d.ts
================================================
/* tslint:disable:only-arrow-functions member-access readonly-keyword no-any */
///
declare module 'browserify-bignum' {
class BigNum {
/**
* Create a new BigNum from a Buffer.
*
* The default options are: {endian: 'big', size: 1}.
*/
static fromBuffer(buffer: Buffer, options?: BigNum.BufferOptions): BigNum;
/** Return true if num is identified as a BigNum instance. Otherwise, return false. */
static isBigNum(num: any): boolean;
/**
* Generate a probable prime of length bits.
*
* If safe is true, it will be a "safe" prime of the form p=2p'+1 where p' is also prime.
*/
static prime(bits: number, safe?: boolean): BigNum;
/** Create a new BigNum from n. */
constructor(n: number | BigNum);
/** Create a new BigNum from n and a base. */
constructor(n: string, base?: number);
/** Return a new BigNum with the absolute value of the instance. */
abs(): BigNum;
/** Return a new BigNum containing the instance value plus n. */
add(n: BigNum.BigNumCompatible): BigNum;
/** Return the number of bits used to represent the current BigNum. */
bitLength(): number;
/**
* Compare the instance value to n.
*
* Return a positive integer if > n, a negative integer if < n, and 0 if == n.
*/
cmp(n: BigNum.BigNumCompatible): number;
/** Return a new BigNum containing the instance value integrally divided by n. */
div(n: BigNum.BigNumCompatible): BigNum;
/** Return a boolean: whether the instance value is equal to n (== n). */
eq(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is greater than or equal to n (>= n). */
ge(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is greater than n (> n). */
gt(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is greater than n (>= n). */
gte(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
le(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is less than n (< n). */
lt(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
lte(n: BigNum.BigNumCompatible): boolean;
/** Return a new BigNum with the instance value modulo n. */
mod(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum containing the instance value multiplied by n. */
mul(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum with the negative of the instance value. */
neg(): BigNum;
/** Return a new BigNum containing the instance value plus n. */
plus(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum with the instance value raised to the nth power. */
pow(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum with the instance value raised to the nth power modulo m. */
powm(n: BigNum.BigNumCompatible, m: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum containing the instance value minus n. */
sub(n: BigNum.BigNumCompatible): BigNum;
/**
* Return a new Buffer with the data from the BigNum.
*
* The default options are: {endian: 'big', size: 1}.
*/
toBuffer(options?: BigNum.BufferOptions): Buffer;
/**
* Turn a BigNum into a Number.
*
* If the BigNum is too big you'll lose precision or you'll get ±Infinity.
*/
toNumber(): number;
/** Print out the BigNum instance in the requested base as a string. Default: base 10 */
toString(base?: number): string;
/** Print out the BigNum instance in the requested base as a string. Default: base 10 */
toString(base?: number): string;
}
export = BigNum;
namespace BigNum {
/** Anything that can be converted to BigNum. */
type BigNumCompatible = BigNum | number | string;
export interface BufferOptions {
/** Can be either 'big' or 'little'. Also accepts 1 for big and -1 for little. Doesn't matter when size = 1. */
endian: string | number;
/** Number of bytes per word, or 'auto' to flip entire Buffer. */
size: number | string;
}
/**
* Turn a BigNum into a Number.
*
* If the BigNum is too big you'll lose precision or you'll get ±Infinity.
*/
export function toNumber(n: BigNumCompatible): number;
/**
* Return a new Buffer with the data from the BigNum.
*
* The default options are: {endian: 'big', size: 1}.
*/
export function toBuffer(
n: BigNumCompatible,
options?: BufferOptions,
): Buffer;
/** Return a new BigNum containing the instance value plus n. */
export function add(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value plus n. */
export function plus(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value minus n. */
export function sub(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value multiplied by n. */
export function mul(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value integrally divided by n. */
export function div(
dividend: BigNumCompatible,
divisor: BigNumCompatible,
): BigNum;
/** Return a new BigNum with the absolute value of the instance. */
export function abs(n: BigNumCompatible): BigNum;
/** Return a new BigNum with the negative of the instance value. */
export function neg(n: BigNumCompatible): BigNum;
/**
* Compare the instance value to n.
*
* Return a positive integer if > n, a negative integer if < n, and 0 if == n.
*/
export function cmp(
left: BigNumCompatible,
right: BigNumCompatible,
): number;
/** Return a boolean: whether the instance value is greater than n (> n). */
export function gt(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is greater than or equal to n (>= n). */
export function gte(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is greater than or equal to n (>= n). */
export function ge(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is equal to n (== n). */
export function eq(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is less than n (< n). */
export function lt(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
export function lte(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
export function le(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a new BigNum with the instance value modulo n. */
export function mod(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum with the instance value raised to the nth power. */
export function pow(
base: BigNumCompatible,
exponent: BigNumCompatible,
): BigNum;
/** Return a new BigNum with the instance value raised to the nth power modulo m. */
export function powm(
base: BigNumCompatible,
exponent: BigNumCompatible,
m: BigNumCompatible,
): BigNum;
/**
* If upperBound is supplied, return a random BigNum between the instance value and upperBound - 1, inclusive.
* Otherwise, return a random BigNum between 0 and the instance value - 1, inclusive.
*/
export function rand(
n: BigNumCompatible,
upperBound?: BigNumCompatible,
): BigNum;
/** Return the number of bits used to represent the current BigNum. */
export function bitLength(n: BigNumCompatible): number;
}
}
================================================
FILE: packages/lisk-cryptography/types/buffer-reverse/index.d.ts
================================================
// tslint:disable only-arrow-functions
declare module 'buffer-reverse' {
export default function(buffer: Buffer): Buffer;
}
================================================
FILE: packages/lisk-cryptography/types/sodium-native/index.d.ts
================================================
// tslint:disable only-arrow-functions variable-name
declare module 'sodium-native' {
export const crypto_box_MACBYTES: number;
export const crypto_sign_BYTES: number;
export const crypto_sign_PUBLICKEYBYTES: number;
export const crypto_sign_SECRETKEYBYTES: number;
export function crypto_box_easy(
cipher: Buffer,
message: Buffer,
nonce: Buffer,
publicKey: Buffer,
secretKey: Buffer,
): void;
export function crypto_box_open_easy(
message: Buffer,
cipherText: Buffer,
nonce: Buffer,
publicKey: Buffer,
secretKey: Buffer,
): boolean;
export function crypto_sign_detached(
signature: Buffer,
message: Buffer,
secretKey: Buffer,
): void;
export function crypto_sign_verify_detached(
signature: Buffer,
message: Buffer,
publicKey: Buffer,
): boolean;
export function randombytes_buf(buffer: Buffer): void;
export function crypto_sign_seed_keypair(
publicKey: Buffer,
privateKey: Buffer,
hashSeed: Buffer,
): void;
}
================================================
FILE: packages/lisk-cryptography/types/varuint-bitcoin/index.d.ts
================================================
// tslint:disable only-arrow-functions
declare module 'varuint-bitcoin' {
export function encode(num: number, buffer?: Buffer, offset?: number): Buffer;
}
================================================
FILE: packages/lisk-elements/README.md
================================================
# Lisk Elements
Lisk Elements is a JavaScript library for [Lisk][Lisk Core GitHub], the blockchain application platform.
[](https://jenkins.lisk.io/job/lisk-elements/job/development/)
[](http://www.gnu.org/licenses/gpl-3.0)
## Installation
### Installation via npm
Add Lisk Elements as a dependency of your project:
```sh
$ npm install --save lisk-elements
```
Import using ES6 modules syntax:
```js
import lisk from 'lisk-elements';
```
Or using Node.js modules:
```js
const lisk = require('lisk-elements');
```
Or import specific namespaced functionality:
```js
import { APIClient, transactions } from 'lisk-elements';
// or
const { APIClient, transactions } = require('lisk-elements');
```
**Note:** If you are installing Lisk Elements as an npm dependency via a GitHub reference, you will need to manually build the distribution files by running the following commands from the root directory of your project:
```
cd node_modules/lisk-elements
npm run build
```
### Installation from source
Our source code is hosted on GitHub. You can build the distribution yourself by cloning the repository, installing the relevant dependencies and running our build script as follows:
```
git clone https://github.com/LiskHQ/lisk-elements.git
cd lisk-elements/packages/lisk-elements
npm install
npm run build
```
## Usage
Access functionality via the relevant namespace. For example, the following will create and (locally) sign a transfer (type 0) transaction, and then broadcast it to the Lisk Testnet.
```js
const transaction = lisk.transaction.transfer({
amount: '123000000',
recipientId: '12668885769632475474L',
passphrase: 'robust swift grocery peasant forget share enable convince deputy road keep cheap',
});
const client = lisk.APIClient.createTestnetAPIClient();
client.transactions.broadcast(transaction)
.then(console.info)
.catch(console.error);
```
Full documentation can be found on the [Lisk documentation site][].
## Packages
| Package | Version | Description |
| ------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------ |
| [lisk-elements](/packages/lisk-elements) | [](https://www.npmjs.com/package/lisk-elements) | Package contains everything |
| [@liskhq/lisk-client](/packages/lisk-client) | [](https://www.npmjs.com/package/@liskhq/lisk-client) | A default set of Elements for use by clients of the Lisk network |
| [@liskhq/lisk-api-client](/packages/lisk-api-client) | [](https://www.npmjs.com/package/@liskhq/lisk-api-client) | An API client for the Lisk network |
| [@liskhq/lisk-constants](/packages/lisk-constants) | [](https://www.npmjs.com/package/@liskhq/lisk-constants) | General constants for use with Lisk-related software |
| [@liskhq/lisk-cryptography](/packages/lisk-cryptography) | [](https://www.npmjs.com/package/@liskhq/lisk-cryptography) | General cryptographic functions for use with Lisk-related software |
| [@liskhq/lisk-passphrase](/packages/lisk-passphrase) | [](https://www.npmjs.com/package/@liskhq/lisk-passphrase) | Mnemonic passphrase helpers for use with Lisk-related software |
| [@liskhq/lisk-transactions](/packages/lisk-transactions) | [](https://www.npmjs.com/package/@liskhq/lisk-transactions) | Everything related to transactions according to the Lisk protocol |
## Tests
To run tests for all packages in lisk-elements, run the following command in the root folder:
```
npm test
```
To run tests for a specific package, run the same command in the relevant package directory.
Example:
```
cd packages/lisk-cryptography
npm test
```
## FAQ
Installation is failing, what should I do?
```
Make sure you are installing in the root folder, not on the package level.
Run `npm run clean` and `npm run clean:node_modules`, then install again.
```
I can't build the package, what should I do?
```
Make sure you first run `npm i`, and then `npm run build` in the root directory.
```
Tests are failing!
```
Make sure you are using the correct version of node and npm.
In our current build we recommend node v8.12.0 and npm v6.4.1.
```
## Contributors
https://github.com/LiskHQ/lisk-elements/graphs/contributors
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-elements/index.html
================================================
Title
Open the console to get started with Lisk Elements.
================================================
FILE: packages/lisk-elements/package.json
================================================
{
"name": "lisk-elements",
"version": "2.0.0",
"description": "Elements for building blockchain applications in the Lisk network",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-elements#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"prestart": "./scripts/prestart.sh",
"start": "./scripts/start.sh",
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s lisk",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js -o ./browsertest.build/browsertest.js -s lisk",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{js,json}\" \"{src,test}/**/*.{js,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/{,/**/}/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11540 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11540) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11540 && cypress run --config baseUrl=http://localhost:11540 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "NODE_ENV=test nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@liskhq/lisk-api-client": "2.0.0",
"@liskhq/lisk-constants": "1.2.0",
"@liskhq/lisk-cryptography": "2.0.0",
"@liskhq/lisk-passphrase": "2.0.0",
"@liskhq/lisk-transactions": "2.0.0",
"@types/node": "10.10.1"
},
"devDependencies": {
"@types/chai": "4.1.5",
"@types/expect": "1.20.3",
"@types/jquery": "3.3.22",
"@types/mocha": "5.2.5",
"browserify": "16.2.2",
"chai": "4.1.2",
"cypress": "3.1.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-elements/scripts/prestart.sh
================================================
read -r -p $'\e[96mDo you want to build Lisk Elements first? [y/N]\e[0m ' should_build
if [[ $should_build =~ ^[Yy]$ ]]
then
npm run build:node
fi
================================================
FILE: packages/lisk-elements/scripts/start.sh
================================================
node -i -e "global.lisk = require('./dist-node').default; console.log('\\x1b[34m', 'The global \`lisk\` was initialised', '\\x1b[0m')"
================================================
FILE: packages/lisk-elements/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { APIClient } from '@liskhq/lisk-api-client';
import * as constants from '@liskhq/lisk-constants';
import * as cryptography from '@liskhq/lisk-cryptography';
import * as passphrase from '@liskhq/lisk-passphrase';
import * as transaction from '@liskhq/lisk-transactions';
export { APIClient, constants, cryptography, passphrase, transaction };
================================================
FILE: packages/lisk-elements/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import 'chai/register-expect';
process.env.NODE_ENV = 'test';
================================================
FILE: packages/lisk-elements/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
APIClient,
constants,
cryptography,
passphrase,
transaction,
} from '../src';
describe('lisk-elements', () => {
it('APIClient should be a function', () => {
return expect(APIClient).to.be.a('function');
});
it('constants should be an object', () => {
return expect(constants).to.be.an('object');
});
it('cryptography should be an object', () => {
return expect(cryptography).to.be.an('object');
});
it('passphrase should be an object', () => {
return expect(passphrase).to.be.an('object');
});
it('transaction should be an object', () => {
return expect(transaction).to.be.an('object');
});
});
================================================
FILE: packages/lisk-passphrase/LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: packages/lisk-passphrase/README.md
================================================
# @liskhq/lisk-passphrase
@liskhq/lisk-passphrase is containing mnemonic passphrase helpers for use with Lisk-related software
## Installation
```sh
$ npm install --save @liskhq/lisk-passphrase
```
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-passphrase/package.json
================================================
{
"name": "@liskhq/lisk-passphrase",
"version": "2.0.0",
"description": "Mnemonic passphrase helpers for use with Lisk-related software",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-passphrase#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s liskPassphrase",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js -o ./browsertest.build/browsertest.js -s liskPassphrase",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{ts,js,json}\" \"{src,test}/**/*.{ts,js,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/**/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11544 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11544) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11544 && cypress run --config baseUrl=http://localhost:11544 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@types/bip39": "2.4.0",
"@types/node": "10.10.1",
"bip39": "2.5.0"
},
"devDependencies": {
"@types/chai": "4.1.5",
"@types/expect": "1.20.3",
"@types/jquery": "3.3.9",
"@types/mocha": "5.2.5",
"browserify": "16.2.2",
"chai": "4.1.2",
"cypress": "3.1.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-passphrase/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import Mnemonic from 'bip39';
import * as validation from './validation';
export { Mnemonic, validation };
================================================
FILE: packages/lisk-passphrase/src/validation.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import Mnemonic from 'bip39';
interface PassphraseRegularExpression {
readonly uppercaseRegExp: RegExp;
readonly whitespaceRegExp: RegExp;
}
interface PassphraseError {
readonly actual: number | boolean | string;
readonly code: string;
readonly expected: number | boolean | string;
readonly location?: ReadonlyArray;
readonly message: string;
}
const passphraseRegularExpression: PassphraseRegularExpression = {
uppercaseRegExp: /[A-Z]/g,
whitespaceRegExp: /\s/g,
};
export const countPassphraseWhitespaces = (passphrase: string): number => {
const whitespaceMatches = passphrase.match(
passphraseRegularExpression.whitespaceRegExp,
);
return whitespaceMatches !== null ? whitespaceMatches.length : 0;
};
export const countPassphraseWords = (passphrase: string): number =>
passphrase.split(' ').filter(Boolean).length;
export const countUppercaseCharacters = (passphrase: string): number => {
const uppercaseCharacterMatches = passphrase.match(
passphraseRegularExpression.uppercaseRegExp,
);
return uppercaseCharacterMatches !== null
? uppercaseCharacterMatches.length
: 0;
};
export const locateUppercaseCharacters = (
passphrase: string,
): ReadonlyArray =>
passphrase
.split('')
.reduce(
(
upperCaseIndexes: ReadonlyArray,
character: string,
index: number,
) => {
if (
character.match(passphraseRegularExpression.uppercaseRegExp) !== null
) {
return [...upperCaseIndexes, index];
}
return upperCaseIndexes;
},
[],
);
export const locateConsecutiveWhitespaces = (
passphrase: string,
): ReadonlyArray =>
passphrase
.split('')
.reduce(
(
whitespaceIndexes: ReadonlyArray,
character: string,
index: number,
) => {
if (
index === 0 &&
character.match(passphraseRegularExpression.whitespaceRegExp) !== null
) {
return [...whitespaceIndexes, index];
}
if (
index !== passphrase.length - 1 &&
character.match(passphraseRegularExpression.whitespaceRegExp) !==
null &&
passphrase
.split('')
[index - 1].match(passphraseRegularExpression.whitespaceRegExp) !==
null
) {
return [...whitespaceIndexes, index];
}
if (
index === passphrase.length - 1 &&
character.match(passphraseRegularExpression.whitespaceRegExp) !== null
) {
return [...whitespaceIndexes, index];
}
return whitespaceIndexes;
},
[],
);
export const getPassphraseValidationErrors = (
passphrase: string,
wordlists?: ReadonlyArray,
expectedWords: number = 12,
): ReadonlyArray => {
const expectedWhitespaces = expectedWords - 1;
const expectedUppercaseCharacterCount = 0;
const wordsInPassphrase = countPassphraseWords(passphrase);
const whiteSpacesInPassphrase = countPassphraseWhitespaces(passphrase);
const uppercaseCharacterInPassphrase = countUppercaseCharacters(passphrase);
const passphraseWordError: PassphraseError = {
actual: wordsInPassphrase,
code: 'INVALID_AMOUNT_OF_WORDS',
expected: expectedWords,
message: `Passphrase contains ${wordsInPassphrase} words instead of expected ${expectedWords}. Please check the passphrase.`,
};
const whiteSpaceError: PassphraseError = {
actual: whiteSpacesInPassphrase,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: expectedWhitespaces,
location: locateConsecutiveWhitespaces(passphrase),
message: `Passphrase contains ${whiteSpacesInPassphrase} whitespaces instead of expected ${expectedWhitespaces}. Please check the passphrase.`,
};
const uppercaseCharacterError: PassphraseError = {
actual: uppercaseCharacterInPassphrase,
code: 'INVALID_AMOUNT_OF_UPPERCASE_CHARACTER',
expected: expectedUppercaseCharacterCount,
location: locateUppercaseCharacters(passphrase),
message: `Passphrase contains ${uppercaseCharacterInPassphrase} uppercase character instead of expected ${expectedUppercaseCharacterCount}. Please check the passphrase.`,
};
const validationError: PassphraseError = {
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
};
const finalWordList =
wordlists !== undefined ? [...wordlists] : Mnemonic.wordlists.english;
return [
passphraseWordError,
whiteSpaceError,
uppercaseCharacterError,
validationError,
].reduce(
(errorArray: ReadonlyArray, error: PassphraseError) => {
if (
error.code === passphraseWordError.code &&
wordsInPassphrase !== expectedWords
) {
return [...errorArray, error];
}
if (
error.code === whiteSpaceError.code &&
whiteSpacesInPassphrase !== expectedWhitespaces
) {
return [...errorArray, error];
}
if (
error.code === uppercaseCharacterError.code &&
uppercaseCharacterInPassphrase !== expectedUppercaseCharacterCount
) {
return [...errorArray, error];
}
if (
error.code === validationError.code &&
!Mnemonic.validateMnemonic(passphrase, finalWordList)
) {
return [...errorArray, error];
}
return errorArray;
},
[],
);
};
================================================
FILE: packages/lisk-passphrase/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { Assertion } from 'chai';
process.env.NODE_ENV = 'test';
Assertion.addProperty('hexString', function handleAssert(
this: Chai.ChaiStatic,
) {
const actual = this._obj;
new Assertion(actual).to.be.a('string');
const expected = Buffer.from(actual, 'hex').toString('hex');
this.assert(
expected === actual,
'expected #{this} to be a hexString',
'expected #{this} not to be a hexString',
);
});
Assertion.addProperty('integer', function handleAssert(this: Chai.ChaiStatic) {
const actual = this._obj;
new Assertion(actual).to.be.a('number');
const expected = parseInt(actual, 10);
this.assert(
actual === expected,
'expected #{this} to be an integer',
'expected #{this} not to be an integer',
);
});
================================================
FILE: packages/lisk-passphrase/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as passphrase from '../src';
describe('passphrase index.js', () => {
it('should export an object', () => {
return expect(passphrase).to.be.an('object');
});
describe('menmonic module', () => {
it('should have the BIP39 Mnemonic module', () => {
return expect(passphrase.Mnemonic).to.be.ok;
});
});
describe('validation module', () => {
it('should have the validation module', () => {
return expect(passphrase.validation).to.be.ok;
});
});
});
================================================
FILE: packages/lisk-passphrase/test/validation.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import Mnemonic from 'bip39';
import { expect } from 'chai';
import {
countPassphraseWhitespaces,
countPassphraseWords,
countUppercaseCharacters,
getPassphraseValidationErrors,
locateUppercaseCharacters,
locateConsecutiveWhitespaces,
} from '../src/validation';
/* tslint:disable: no-magic-numbers */
describe('passphrase validation', () => {
describe('countPassphraseWhitespaces', () => {
describe('given a valid passphrase', () => {
const expectedAmountOfWhitespaces = 11;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with an extra whitespace at the end', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge ';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with an extra whitespace at the beginning', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
' model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with extra whitespaces between the first words', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with extra whitespaces between all words', () => {
const expectedAmountOfWhitespaces = 22;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with tab in the beginning', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'\tmodel actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with vertical tab in the beginning', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'\vmodel actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with form feed in the beginning', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'\fmodel actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with nonbreaking space in the beginning', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'\u00A0model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with byte order mark in the beginning', () => {
const expectedAmountOfWhitespaces = 12;
const passphrase =
'\uFEFFmodel actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
describe('given a passphrase with no whitespaces', () => {
const expectedAmountOfWhitespaces = 0;
const passphrase =
'modelactorshalloweightglueupperseatlobsterreasonlabelenlistbridge';
it('should return the expected amount of whitespaces', () => {
return expect(countPassphraseWhitespaces(passphrase)).to.be.equal(
expectedAmountOfWhitespaces,
);
});
});
});
describe('countPassphraseWords', () => {
describe('given a valid passphrase', () => {
const expectedAmountOfWords = 12;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the amount of words', () => {
return expect(countPassphraseWords(passphrase)).to.be.equal(
expectedAmountOfWords,
);
});
});
describe('given a passphrase with 13 words', () => {
const expectedAmountOfWords = 13;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge model';
it('should return the amount of words', () => {
return expect(countPassphraseWords(passphrase)).to.be.equal(
expectedAmountOfWords,
);
});
});
describe('given a passphrase with 9 words', () => {
const expectedAmountOfWords = 9;
const passphrase =
'model actor shallow eight glue upper seat lobster reason';
it('should return the amount of words', () => {
return expect(countPassphraseWords(passphrase)).to.be.equal(
expectedAmountOfWords,
);
});
});
describe('given a passphrase with 12 words and extra whitespaces', () => {
const expectedAmountOfWords = 12;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should ignore the whitespaces and return the amount of words', () => {
return expect(countPassphraseWords(passphrase)).to.be.equal(
expectedAmountOfWords,
);
});
});
describe('given a passphrase with no words but whitespaces', () => {
const expectedAmountOfWords = 0;
const passphrase = ' ';
it('should ignore the whitespaces and return the amount of words', () => {
return expect(countPassphraseWords(passphrase)).to.be.equal(
expectedAmountOfWords,
);
});
});
describe('given an empty string passphrase', () => {
const expectedAmountOfWords = 0;
const passphrase = '';
it('should return the amount of words', () => {
return expect(countPassphraseWords(passphrase)).to.be.equal(
expectedAmountOfWords,
);
});
});
});
describe('countUppercaseCharacters', () => {
describe('given a passphrase without uppercase character', () => {
const expectedAmountUppercaseCharacter = 0;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return the number of uppercase characters', () => {
const uppercased = countUppercaseCharacters(passphrase);
return expect(uppercased).to.be.equal(expectedAmountUppercaseCharacter);
});
});
describe('given a passphrase with uppercase character', () => {
const expectedAmountOfCapitalCharacters = 4;
const passphrase =
'Model Actor shallow eight glue upPer seat lobSter reason label enlist bridge';
it('should return the amount of uppercase character', () => {
const uppercased = countUppercaseCharacters(passphrase);
return expect(uppercased).to.be.equal(
expectedAmountOfCapitalCharacters,
);
});
});
describe('given a passphrase with all uppercase character', () => {
const expectedAmountOfCapitalCharacters = 65;
const passphrase =
'MODEL ACTOR SHALLOW EIGHT GLUE UPPER SEAT LOBSTER REASON LABEL ENLIST BRIDGE';
it('should return the amount of uppercase character', () => {
return expect(countUppercaseCharacters(passphrase)).to.be.equal(
expectedAmountOfCapitalCharacters,
);
});
});
});
describe('locateUppercaseCharacters', () => {
describe('given a string without uppercase character', () => {
const testString = 'a string without uppercase character';
it('should return an empty array', () => {
return expect(locateUppercaseCharacters(testString)).to.be.eql([]);
});
});
describe('given a string with uppercase character', () => {
const testString = 'a String with SOME uppercase characteR';
const uppercaseCharacters = [2, 14, 15, 16, 17, 37];
it('should return the array with the location of the uppercase character', () => {
return expect(locateUppercaseCharacters(testString)).to.be.eql(
uppercaseCharacters,
);
});
});
});
describe('locateConsecutiveWhitespaces', () => {
describe('given a string without whitespaces', () => {
const testString = 'abcdefghijklkmnop';
it('should return an empty array', () => {
return expect(locateConsecutiveWhitespaces(testString)).to.be.eql([]);
});
});
describe('given a string with whitespaces', () => {
const testString = 'abc defghijk lkmnop';
it('should return an empty array', () => {
return expect(locateConsecutiveWhitespaces(testString)).to.be.eql([]);
});
});
describe('given a string with a whitespace in the beginning', () => {
const testString = ' abc defghijk lkmnop';
const expectedWhitespaceLocation = [0];
it('should return the array with the location of the whitespace', () => {
return expect(locateConsecutiveWhitespaces(testString)).to.be.eql(
expectedWhitespaceLocation,
);
});
});
describe('given a string with a whitespace in the end', () => {
const testString = 'abc defghijk lkmnop ';
const expectedWhitespaceLocation = [19];
it('should return the array with the location of the whitespace', () => {
return expect(locateConsecutiveWhitespaces(testString)).to.be.eql(
expectedWhitespaceLocation,
);
});
});
describe('given a string with extra whitespaces', () => {
const testString = 'abc defghijk lkmnop ';
const expectedWhitespaceLocation = [4, 14, 21];
it('should return the array with the location of the whitespaces', () => {
return expect(locateConsecutiveWhitespaces(testString)).to.be.eql(
expectedWhitespaceLocation,
);
});
});
describe('given a string with extra whitespaces with special characters', () => {
const testString = 'abc defghijk\t \nlkmnop \u00A0';
const expectedWhitespaceLocation = [4, 14, 15, 23];
it('should return the array with the location of the whitespaces', () => {
return expect(locateConsecutiveWhitespaces(testString)).to.be.eql(
expectedWhitespaceLocation,
);
});
});
});
describe('getPassphraseValidationErrors', () => {
describe('given a valid passphrase', () => {
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return an empty array', () => {
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql([]);
});
});
describe('given a passphrase with valid 15 words passphrase', () => {
const passphrase =
'post dumb recycle buddy round normal scrap better people corn crystal again never shrimp kidney';
it('should return an array with the errors when validating with default expectedWords', () => {
const errors = [
{
actual: 15,
code: 'INVALID_AMOUNT_OF_WORDS',
expected: 12,
message:
'Passphrase contains 15 words instead of expected 12. Please check the passphrase.',
},
{
actual: 14,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: 11,
location: [],
message:
'Passphrase contains 14 whitespaces instead of expected 11. Please check the passphrase.',
},
];
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql(
errors,
);
});
it('should return an array with the errors when validating with lower expectedWords', () => {
const errors = [
{
actual: 15,
code: 'INVALID_AMOUNT_OF_WORDS',
expected: 12,
message:
'Passphrase contains 15 words instead of expected 12. Please check the passphrase.',
},
{
actual: 14,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: 11,
location: [],
message:
'Passphrase contains 14 whitespaces instead of expected 11. Please check the passphrase.',
},
];
return expect(
getPassphraseValidationErrors(passphrase, undefined, 12),
).to.be.eql(errors);
});
it('should return an array with the errors when validating with higher expectedWords', () => {
const errors = [
{
actual: 15,
code: 'INVALID_AMOUNT_OF_WORDS',
expected: 18,
message:
'Passphrase contains 15 words instead of expected 18. Please check the passphrase.',
},
{
actual: 14,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: 17,
location: [],
message:
'Passphrase contains 14 whitespaces instead of expected 17. Please check the passphrase.',
},
];
return expect(
getPassphraseValidationErrors(
passphrase,
Mnemonic.wordlists.english,
18,
),
).to.be.eql(errors);
});
it('should return an empty array when validating with exact expectedWords', () => {
return expect(
getPassphraseValidationErrors(passphrase, undefined, 15),
).to.be.eql([]);
});
});
describe('given a passphrase with an extra whitespace in the beginning', () => {
const passphrase =
' model actor shallow eight glue upper seat lobster reason label enlist bridge';
const passphraseInvalidMnemonicErrors = [
{
actual: 12,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: 11,
location: [0],
message:
'Passphrase contains 12 whitespaces instead of expected 11. Please check the passphrase.',
},
{
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
},
];
it('should return the array with the errors', () => {
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql(
passphraseInvalidMnemonicErrors,
);
});
});
describe('given a passphrase with an extra whitespace in the end', () => {
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge ';
const passphraseInvalidMnemonicErrors = [
{
actual: 12,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: 11,
location: [76],
message:
'Passphrase contains 12 whitespaces instead of expected 11. Please check the passphrase.',
},
{
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
},
];
it('should return the array with the errors', () => {
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql(
passphraseInvalidMnemonicErrors,
);
});
});
describe('given a passphrase with too many whitespaces in between words', () => {
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
const passphraseInvalidMnemonicErrors = [
{
actual: 13,
code: 'INVALID_AMOUNT_OF_WHITESPACES',
expected: 11,
location: [31, 43],
message:
'Passphrase contains 13 whitespaces instead of expected 11. Please check the passphrase.',
},
{
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
},
];
it('should return the array with the errors', () => {
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql(
passphraseInvalidMnemonicErrors,
);
});
});
describe('given a passphrase with uppercase characters', () => {
const passphrase =
'modEl actor shallow eight glue upper sEat lobster reaSon label enlist bridge';
const passphraseWithUppercaseCharacterErrors = [
{
actual: 3,
code: 'INVALID_AMOUNT_OF_UPPERCASE_CHARACTER',
expected: 0,
location: [3, 38, 53],
message:
'Passphrase contains 3 uppercase character instead of expected 0. Please check the passphrase.',
},
{
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
},
];
it('should return the array with the errors', () => {
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql(
passphraseWithUppercaseCharacterErrors,
);
});
});
describe('given a passphrase that is an invalid mnemonic passphrase', () => {
const passphrase =
'model actor shallow eight glue upper seat lobster reason label engage bridge';
const passphraseInvalidMnemonicError = [
{
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
},
];
it('should return the array with the error', () => {
return expect(getPassphraseValidationErrors(passphrase)).to.be.eql(
passphraseInvalidMnemonicError,
);
});
});
describe('given a passphrase that uses the correct wordlist for the passphrase', () => {
const wordlist = Mnemonic.wordlists.english;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
it('should return an empty array', () => {
return expect(
getPassphraseValidationErrors(passphrase, wordlist),
).to.be.eql([]);
});
});
describe('given a passphrase that uses a different wordlist for the passphrase', () => {
const wordlist = Mnemonic.wordlists.spanish;
const passphrase =
'model actor shallow eight glue upper seat lobster reason label enlist bridge';
const passphraseInvalidMnemonicError = [
{
actual: false,
code: 'INVALID_MNEMONIC',
expected: true,
message:
'Passphrase is not a valid mnemonic passphrase. Please check the passphrase.',
},
];
it('should return the array with the error', () => {
return expect(
getPassphraseValidationErrors(passphrase, wordlist),
).to.be.eql(passphraseInvalidMnemonicError);
});
});
});
});
================================================
FILE: packages/lisk-transactions/LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
================================================
FILE: packages/lisk-transactions/README.md
================================================
# @liskhq/lisk-transactions
@liskhq/lisk-transactions is containing everything related to transactions according to the Lisk protocol
## Installation
```sh
$ npm install --save @liskhq/lisk-transactions
```
## License
Copyright © 2016-2018 Lisk Foundation
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the [GNU General Public License](https://github.com/LiskHQ/lisk-elements/tree/master/LICENSE) along with this program. If not, see .
***
This program also incorporates work previously released with lisk-js `v0.5.2` (and earlier) versions under the [MIT License](https://opensource.org/licenses/MIT). To comply with the requirements of that license, the following permission notice, applicable to those parts of the code only, is included below:
Copyright © 2016-2017 Lisk Foundation
Copyright © 2015 Crypti
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[Lisk Core GitHub]: https://github.com/LiskHQ/lisk
[Lisk documentation site]: https://lisk.io/documentation/lisk-elements
================================================
FILE: packages/lisk-transactions/fixtures/invalid_transactions.json
================================================
[
{
"type":4,
"amount": "0",
"fee": "3000000000",
"recipientId":null,
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp":54196079,
"asset": {
"multisignature": {
"min": 0,
"lifetime": 35,
"keysgroup": [
"+cac3545e2fa5b9fe4a41a66ce86adbb0322587137e5289b06ba4527673a85574",
"+09e85edafad8b6e6191e1d989c58c5825b0596d5d5f5598e854eeabdffd2a850",
"+29d8260d35f110f33d988f6a23d29153c1a344a339894774690fb9b6b6bb494e",
"+346719e114848b4fbf9839836ebeb066b2898d872aef0dd315594b83d2fca1a2",
"+01b014d50765d9f705b720d6376c792afca3da4ba2798bc65626a97494579790"
]
}
},
"signature": "5d2acb6cc15f8de7a2531ba6a1e7725d82d07789672605e286f4ff11a19e0fb69034411f99c66267ead9245ceee54977d46a5427bdf651f8277d6908d2fd5e03",
"id": "14026504139568973606"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"multisignature": {
"min": 0,
"lifetime": 18,
"keysgroup": [
"+740834a59435d283fd3fb30ad5d7cbde2550e82471b73abedcffb61eaa6298e4",
"+9bc8972fb01b70eb4624df5d4d4c7c00a51fd73958c50efaefe55260889aedd6",
"+66a68de8047bbe788f5ec5fbae6baf84c6438606f4e6fdf91b791113a0506ea6",
"+5f7c4b9b6f976a400dba8d0cc7f904603ea4ffe1d8702c80576a396037c49970",
"+4e4a6b5cf7b8840ba521dfae5914f55ec3805c7d5cf25dfbf44fac57f9c5f183"
]
}
},
"signature":
"57b54da646c7567df86fec60aa57a40bfadb6cdc65cccecfc442c822a7b0372f4958a280edd3fc2d83d38e2d3bf922a1da01249c500f0309a9638e941a21c501",
"id": "13916871066741078807"
},
{
"type": 6,
"amount": "897386",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"81db12eccf99f92ffc5963383acb0b275777de860e7d2251d1432a1eeb46fb858d41737e68ac5cb61eab5adc7d8f6f6db8905767e997bb445babf6004ab1bb00",
"id": "14834734940279241743"
},
{
"type": 7,
"amount": "761715",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"outTransfer": { "dappId": "720987408", "transactionId": "40486129" }
},
"signature":
"69a84e9a883a8f624cb5dfc80f7d734f0eff9c2d2193f94238a0636b1a56afaeed8261b46de518f9ca7c9efe910628bdce9ff4a78fe86ef1a08a913486142e02"
},
{
"type": 6,
"amount": "737434",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"7cb7d1c9f37aa5d753cd241d74b20fcd2a1540b27f7d5628b865b9b0e806eba23a0ca7ed043f73a5a881778c9cabd40ef836e0742226c60389075433b725860d",
"id": "10020668765583935219"
},
{
"type": 7,
"amount": "646565",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"outTransfer": { "dappId": "336803878", "transactionId": "856503447" }
},
"signature":
"caae702b9b12bd423cd2f3c742135b459149fb484f9479551bb0f1374c6f805cf881cb64f52b797770a512bdaaabf8404a22857af6713ac70035f5e9359fb60b"
},
{
"type": 6,
"amount": "33067",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"33ce5ae051be0a10ad91ce33ee7636856e53eb0d6dfc3532333bbd11d832d7fa5a7f1cf3a3221625cd4c4c4a743587c5286a0e0166e7c2a4317bb4439f3ff008",
"id": "12483552871112483989"
},
{
"type": 7,
"amount": "966482",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"outTransfer": { "dappId": "275792609", "transactionId": "421790462" }
},
"signature":
"7d4cc20b24d9486a26bd74b14ba24ef1d12381f04434f125e8efaa322c1b3c1cb5c357a3b7c47fb4097fa88a0751360a37c28e6b03890f4955d51fff7948ff05"
},
{
"type": 6,
"amount": "693810",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"1fdab67596b6201fc73d741c1d5e0c0b8fa8536ce19fc8625a0cd41db84e97575e862037db1377cdd4b7d2520b0541fe52800117ae5297a42bb10de13b451b02",
"signSignature":
"839c9397237065c0e676db1687ebf307c261382f34ac0c356d4a009d9f997c2bbeee0d48fa0ccd538543181efee63ce2810e9de144b13c1d5c78e95e8d097008",
"id": "9781155639793361245"
},
{
"type": 7,
"amount": "476088",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"outTransfer": { "dappId": "102606108", "transactionId": "549685977" }
},
"signature":
"01c46d39654e2b7708c998fe813e32f37fe1fe9a3f6547faefcec8743392909f119a8c76a63cce76d2bf9969b7adb80c75d31c72e2f9f98aa6d9ac9418e07e0c",
"signSignature":
"272815f308cabb04e4d8a817925758dc9d63e97425593c8e344089fead1936e6bcc51d3c49141fc97ea4eb7fbed67cd3f5bb89a979d121e174aaf526d23b210a"
},
{
"type": 6,
"amount": "166413",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"f2b1a66d9bd8ae0c1b3404fe397a11bd696e5aea274e6a8d9fea2f976503d006b8ca65484daf2498f854a0c0109b924b653a8d6ba31a568cb70727b7d3472902",
"id": "9501694969515165251"
},
{
"type": 7,
"amount": "835151",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"outTransfer": { "dappId": "614143983", "transactionId": "749591467" }
},
"signature":
"646cd6cbe9f385bfa4f914b66a675a77080a3c1093278cfbca16d3d7fbf768350c9a7e270a8e5a72347e2792d3cfc770f3a3bb9ea542c300cba3976f34bd040e"
},
{
"type": 6,
"amount": "270355",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"8a22d0b245bccd8f53ea7acd9b137bc3c7ed76a666318e7969aee45e67e75ab552dff73ec7c95c0653c2308691d068499be792d7229507c23ddd6d126a905d00",
"signSignature":
"a504c8a7ef794b6ec99aa9c914f9e562ce8e18a5797bdc92ff03a7cc479600e3f3d8cd2b3cf478b7006f996d174ceae94297568c27aab3c43c8925c1e760af08",
"id": "4482291724705265307"
},
{
"type": 7,
"amount": "621696",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"outTransfer": { "dappId": "31057994", "transactionId": "377678276" }
},
"signature":
"8c9abc118100d6aa016acae15ed4d10ce168b3aab9cc7d25f3bde38f2f198a3fcb729f670bdfeaba1b8e5a73192d3e115fa174e784e224a61439c00f1fef1304",
"signSignature":
"fdbab8d4029624fc82e372dae3ebc8636142b83e894c5c8c32f1b912a751b894640e0ed514b72ee1c67d8bcf6ee9ea140de7e45e58c849c16598ffe4dbb85b06"
},
{
"type": 6,
"amount": "825188",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"ea3a2b7655d2be581f0c08af121ce114f5ffff7b3149727558f8c6775b266c738a7abc8f3fc2baa55d4f445f09ec206996f196a59c5f8502fc36121f9149ed0c",
"id": "6562982313425129534"
},
{
"type": 7,
"amount": "628348",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"outTransfer": { "dappId": "49615750", "transactionId": "296407938" }
},
"signature":
"67d0443b82b67d4fc2c287c3241fe44c40f68fc2df14e30d3746e463df2b7533f0cb4b4bca055a3f767d07f81a84c5843ad4b346554bfbe9cb1244a69b345e0d"
},
{
"type": 6,
"amount": "369464",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"6042833a4578b512a0dc8451ad4a92aec63d684eb2ba4fd9602b4c7235ec72fac12bda1ff984132f7ec36c440a3f4b9f20c4634169309ed430f4434968fa8b03",
"id": "4907759462496699682"
},
{
"type": 7,
"amount": "426107",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"outTransfer": { "dappId": "170489289", "transactionId": "11189562" }
},
"signature":
"fc703ab98d6f25eb9617fab51a22cebdc8e340047c0b600bbf0fb216f9ac73520b10bbc6375ee3eafceb3c459f57dd0b661b4c19d114364cefec6e964bad5b08"
},
{
"type": 6,
"amount": "405432",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"cac1442ade22a5ca056fcd157188a54f7f3648513ed1d8bbcd0656d7a0ae8aae1711b008623493f174d6318323e7e99ce7b9033a2f2b63d5fdb0406c598eec07",
"id": "11187309556374500080"
},
{
"type": 7,
"amount": "728029",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"outTransfer": { "dappId": "433910011", "transactionId": "995526027" }
},
"signature":
"e817a3bfe8570d13a7a728bcfd108168e47ab48e748424793dd866f61617f1786fc3908c8eaa20f470ae1e11363f8fdc55d64d8e08d0dbc399cccea38ecacc05"
},
{
"type": 6,
"amount": "881374",
"fee": "10000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": { "inTransfer": { "dappId": "1000000" } },
"signature":
"f9facd4dd0b278e3fdca44e6b5527ff4d71f65fb05d1a993cc094f7a6e08118d96ad9103c7577c9efff41d3deec08ffb06346ab27aeff800d499785b53bea40d",
"signSignature":
"ddbe2671cb80cf478b581772242e20d49b8f88445928f8c685ea06a83733a7c7abec31c53f52f1962126abc6e1e03b2c8c7b881f6a3d6808496eb500498b730b",
"id": "10748675444711410396"
},
{
"type": 7,
"amount": "370999",
"fee": "10000000",
"recipientId": "1859190791819301L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"outTransfer": { "dappId": "763580659", "transactionId": "89998498" }
},
"signature":
"8041323c405e23fc8ebaaf7ded1a61e1922c29643d6ab5cf536655fb69380d7e64a158198a21cd34faa06ed1777321f403421fe59fc1b4c40087c19ab47eda0c",
"signSignature":
"177664c1e4afc88462f44f8af6192d36d435bf9457d2466e9ced8b52d44eb740be03232a6a9e0467762cf336bbd155fba04dd0a74cb7a6938ee976453bf6070b"
}
]
================================================
FILE: packages/lisk-transactions/fixtures/transactions.json
================================================
[
{
"type": 1,
"amount": "0",
"fee": "500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54316324,
"asset": {
"signature": {
"publicKey":
"f9666bfed9ef2ff52a04408f22f2bfffaa81384c9433463697330224f10032a4"
}
},
"signature":
"69d0c7bc50b82465e2b0885cebc422aa9cd575050dc89905e22a6e2cc88802935c6809a59a2daa04ca99623a6fef76b7d03215ed7f401b74ef5301b12bfe2002",
"id": "6998015087494860094"
},
{
"type": 0,
"amount": "4008489300000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196076,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"1518a69983e348359f62a8e740f6f5f08c0c3cad651e5116bf991bc5a4b4cfb8bf8c033a86e30f596fac80142df5a4121400ac2e9307614a143ffd75cc07c20b",
"id": "7507990258936015021"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196076,
"asset": {
"votes": [
"+0d720b72d179bdd07621cf0b6b68fd23a96777e0833f35b9d22b873c80f9b336",
"+44b58b4a9d8d0af057ada7c90bb90e30be47326c8a102c8bc6604e98ca93d1ef",
"+a8bde4a93381d7cb756611262af04844fb0a182fb9de515a3c4f068daa05c695",
"+7c5c08669e9d1366bfe6ae17ca6a054e92610358e2dc82865a826eac738fdb6a",
"-7742a72b4eb62bd994e2f1e4b44637fbce9fc1fa900080636b2f7eff40872fa6"
]
},
"signature":
"1d9b94e30ff2206b9de6406d9d221c751af00a300ea26fa479da3dd3bb1266d4461f8ae19a08b42ecf6648a86dc6969e965f8a617cd18c1d1ce6126d683e8605",
"id": "6128439024328469721"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196076,
"asset": {
"delegate": {
"username": "RLI0",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"3147b031c6fa71cbfc3f8a74b9cd5ed85b56b01f00e9df13244c354d43bfa90ec89dd2fe66d8e5107233073b5aac387cb54d1454ac68e73d43203d1f14ec0900",
"id": "5337978774712629501"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"multisignature": {
"min": 5,
"lifetime": 1,
"keysgroup": [
"+6638548d991d49e2b41bf15b595fa19749b25c58483e7e8fc926038074571ebf",
"+a0ed6137800e9a65f796e423d9ebece0a7df53f0049e90eebc2e597452de69ed",
"+4bb9e15fa15cbe87d19b6854474d57c3aa515deb586548bb515630dc7121d021",
"+068bcac57c9d988f0a03bab381785c67ef4b63ca8047f41863fb2a0202aa88a5",
"+261fb86d60785e208ba7541db9ab56d3e02fcf9357a25bf859f826e87cadb816"
]
}
},
"signature":
"46f6ce8da1b5948aaa63a51cf28913210d356cc27a2cc952a2bf1b88f47d6cd6f250f8d907b9a4e0c531a66c601b50aa483a461e803412f2ae9543d99155970f",
"id": "15911083597203956215"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"dapp": {
"category": 0,
"name": "jSFFSiM4HZ91x7DXnOu",
"description": "HQWQewqxZ0AA330r",
"tags": "HReDOT69QpOGfR1ELav",
"type": 0,
"link": "qEXks",
"icon": "mJM14TJiZSe3OmvYXpkaSqk6pr"
}
},
"signature":
"d4888d8e916127358c5f6417ae4cc110e5509f32ef35589401e1a147e6b20a32fd280567d10f2d11224a94a32db0088a834138408d3a6d490f6be34a57e36207",
"id": "6368378298793859048"
},
{
"type": 0,
"amount": "8969127700000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196078,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"335033784ce58916373bfdec8c6b0a279155d3bf1f418e42e8a0804fa45906e5f71e8d0a34cb1bcd38397788efaf231e56d6d3527c3a08625ca46c1512d51c0b",
"id": "4937270977123783749"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"votes": [
"+900fcb60a949a9269af36f0da4a7da6e5b9a81bafb1929b2882f8aeda5960ff0",
"+083d534a51c358e6dce6d43f4f0de8abf5bb1d8b8ee7fe817c5b225bb4c46fd8",
"+2027d6af78cc6b10d1fa9712dbb6241b67531552c2d3a688d8565c37b8a307ff",
"+9e3f52823ebdb0e07649b1d260f864691b81a4f7e18fdf8935bbb1bcfe454663",
"-18982fb4caf0cae685a3ca44fe91445c26bef542f09fc8ea0e25fd33fd948fd7"
]
},
"signature":
"45010721b4ed0424a003da5e82f5917a8895d99adb0bf9509b65cd7dbd14653efd9ed0b4f52a4d1ab7da89e3b8ef33337a67737af451df06bee51b124f741c0b",
"id": "9048233810524582722"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"delegate": {
"username": "TYX",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"660ba7172a25a19819344c1ac99f0b2532915ede18405563fcf454ff22278f1c8f33bf6fe44a29ac2a4daabf3edd1551809bb081766ef1a5b8a0251c5a656103",
"id": "17457098940654976683"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"multisignature": {
"min": 3,
"lifetime": 34,
"keysgroup": [
"+ed2f2b9e8f377f77ad721ad572de0575796789b7a5b29cbafdc294a1f86f8a72",
"+d2e3dfb830bbbd6dd10ec6022dffac9d189343e7255f89346ede6ffbd66327fd",
"+e77283fe326d473aff78c74dac627538b7e761a7efd65edbc425c14916657b7a",
"+5124a5c4f48714c52e5242a124545fe7bf47e4bcdc03f80c485d55c886a98013",
"+ced89d652d99de651d8d1e5f30661c9a5780bb9b2955d11bf84ed1ed08abe60f"
]
}
},
"signature":
"97f663b356609227009f664e6072f58b43dbd5dc17f7586e9dad9511fe3272c813f81353135b5831e3c930c5669f0223402047694bc31f61276254c0ec5b170d",
"id": "16196080519305519880"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"dapp": {
"category": 0,
"name": "",
"description": "wE3f2s3OYt7eY7WjbFy",
"tags": "BcnXy7fBVgp",
"type": 0,
"link": "4",
"icon": "IBaIGbiH"
}
},
"signature":
"8ad74d9fe9db6e9750986bce3890821e8611fa840f86019b891a9d30d5d53371372f0ebc79dab2854e5c0bb62cab3e3a49d76ae05f1f424a1112df0fda771b03",
"id": "4804584599866287174"
},
{
"type": 0,
"amount": "4054494300000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196078,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"7b3f813eb3b130e9d31b74371b2a221fa2915fed0fc4fd435d42ea89c7cb76d7eafb105a973080e00bf54e62f48eb969cb88a4371ffec3c225c2821f9619af08",
"id": "11811758250853952228"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"votes": [
"+3b458651eb45887a10a95489dad3f14a708c8eb2c50af6abfcfb753d4b01dcb3",
"+0a8e2446495959401daa8adcf7646276eaf49e1cf10993e36ac5a21a39945a7d",
"+765a399060d14680c7a12246e642b7cb46fede3dfc8f43c6cb57dfefbc1a4533",
"+586e1f97641d9c736737e9755f658461ed961aa475be28361b8331468a2b8fa0",
"-332438da41f1c8019098b148482d51fa58dc026cd3fb49d77d4f7356ff0c063d"
]
},
"signature":
"15cbfa6843efa6c6574c986d371ab689cfdddc958ad6ec7b7a8024f98559478cbfae09c7cf4e62e30ffd1331e24951c534db96d3349f828ae9514578f98b120e",
"id": "11944214126253524732"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"delegate": {
"username": "g0chqJUQp",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"0271091d6055e831ad6c14b6a9fecd77dbf44c4a20285e4df51302134f8ffccc3dcc73ba2a8a5ea1fcebeafd65943f503ffee41a4283f798e7a9996b5eb5a807",
"id": "10417213059747712454"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"multisignature": {
"min": 3,
"lifetime": 13,
"keysgroup": [
"+9f207919be15e45a5fd89ec5d699d72390a2ccc6eaaf587d88eefa46a7f7c01c",
"+f209131118dd05585d3131b5250caf8737b712c63dfc56dcf7d9678e0551b4a8",
"+9d2a2afd25ee6c48b4aef7f673bffde98c6bf278997a917cce739568eefd99e3",
"+163cb0f7d9da97611350f72741fececd41d066e45dc8370076b0fabc951232a7",
"+66c085d46ec6c3b7c9270f9e62b113ce4248c7bd0e5924355307c57fb8ef93ae"
]
}
},
"signature":
"76a4b1df52bb97bedeaeff199a8ee7408d1bdab3ba735ff70b7e0a362d891d622726814b12499ef2b01b825717f92ba6d3c4ffc5c6fb0a22035b63a140ad4407",
"id": "8904533490777066124"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"dapp": {
"category": 0,
"name": "lF7s",
"description": "BZqgVHKUZjsyr5",
"tags": "AYV",
"type": 0,
"link": "dzQ3leCut",
"icon": "sJoKLJOdAvtdktEl5hzaIttiN"
}
},
"signature":
"99c6e43a6a06caab60b6147dd0eba6c7afbdc4b4f6b82e6911100a454ca1252dfca560a5ec65f01bb03f71fb5e37d8f3ad0255f77b809991acfcf42504eb0e01",
"id": "16584586901330410057"
},
{
"type": 0,
"amount": "8184360100000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196078,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"53c1cb90f379c1afa1b7fb7b7c79689d02ed96da32cc337b511d48573da35fdf261f2f85f744a01a62866c2d672ad1a73286f94ef6af494eb4890f0b6a4a0c02",
"id": "8699527477254187757"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"votes": [
"+dd8fb02b092402d4bb4114cc7b79b83fe7b30a18fceaa62d8a47f737604a34ff",
"+82e42e6f8f9f4d910d8a883e9163fa46190064c3d112b05f4802fd92fa55b431",
"+ffcf0152971388d89b007ab293349e55979bf3c81dfb2a41bc5304d3b4140503",
"+2771daeae7b042c8927c7cf86821bee85f27914c8be3b185a9ff2d749852f923",
"-64b517fc24df9e1cbc2797b6bdb0747912f3efa5c2b863d53fba95788ef6d099"
]
},
"signature":
"e1ea529a6c252e4a50408693378a38aec68bbd474ee8562b33a3572d5ce38a69a515f7448de5185be0fb2dfc23652c43ea0cc3490683df185b052952f9ec610e",
"id": "1804328474810539521"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"delegate": {
"username": "mUUn",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"f5a2c0946bcae73ce24a29dbbdc16c1f3fd897ece7de5ae6d2a891f98673b54106f0d516398960f545b00cc0cdbd131a14590b796185e7e72d66fecdb9eab206",
"id": "13111698433238994230"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"multisignature": {
"min": 5,
"lifetime": 14,
"keysgroup": [
"+465f0eed0a5614af4c282b35e4f8cc7b8010783aaf848a8c073386f619208864",
"+a5df78890691147c6b13c9330e2e5fabebfa52ef1eb5d79dfeb3d9892d4c8f8b",
"+ad8a0767c7cc1e566888902c5588c35c6f75ba985777f6d2f23e428a9c7c470d",
"+f7b14239c88d7c1e6931532c1a248080bf24591b2b4226748fa0b4b0b060808d",
"+744d25d065b806d6a4028a8f9de7a4342b8cc8b647e04e7ff66f7ea53df9f8c4"
]
}
},
"signature":
"c0f3f4ec468b647823511b81e199af569211269f898cbd872291b0f609608815526f837ba18038cfca3b5002e01a0f7054cbc6b6f74de66a275eda4909124206",
"id": "8649508251318979973"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"dapp": {
"category": 0,
"name": "5pATdfOO",
"description": "MwNovspfAO0jTsY0o",
"tags": "HP2qmZaRajMVNaSxB9NypeS19HRfoknG1WlE4l",
"type": 0,
"link": "EblohNQI",
"icon": "D"
}
},
"signature":
"f56cca3239759dca1db8be70124e8a3ba1a64e4d1d8e7299e27d82d96fa386cc84bed703897bd60f3b862dc1d201c1688af75dcb572f048ccfc3e69a38c24d0e",
"id": "6415932520816963164"
},
{
"type": 0,
"amount": "3649003300000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196078,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"8953d989a4be6d2d0ab25dbb11b1268a21ce3681aba6c0fe391b2b7c18179f52af5440aca8b27794eb27d29b41a306f931882190a1ad922c274fb9bc5be63303",
"signSignature":
"0ccd222e27835d041622c469da6d69c1720202f6bb8258b7199a690b86d1671b45ef8ad03ff0b78a8dd91c38a9fad694d9186f414e83f9ad076e69b72ab02c0d",
"id": "10897127897715572989"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"votes": [
"+791dbbf8e7f52eb253611c92758a25aed0b1ced2c1449272c251dde27a63e164",
"+2b0fa724137c99da93590c1fbe2f2a988cc28b1b7f66e17942d7c3026b19bd65",
"+bc97c09776318348138aaf7031b642a665bb3d2bd5e76ccc525dcf74fae960fe",
"+b3036b5bde0f106f86f72245ca238148e7871235c236fb41bb08d8d0960ca807",
"-e97c6e9027d940686a92cc56069822ef64e17926ff677f12c88196d0441b8a8a"
]
},
"signature":
"ebf2a10ef69c5282b554b9d23c21c9884e558376f42972515d4d4397b535bb2d521ccfe48f28468a0371e00f2af7550fec1e17d374d75c1abc15051341b4cc00",
"signSignature":
"640fd85321213dcfa16ce7fcad219aeeb284119016cab7650b83beca2634650e834308996b85861c8046997344d1ff64be7c56bb43f77cea26655d2c17b6b608",
"id": "17799333624445334933"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"delegate": {
"username": "r9bGwAqXG1pOnVL",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"5c0b596006acb565cee01d22b5de2e60dde69df3c5cbf2e96c4242cb80811f205ae05fcf1110810bd477ad3e67cf42e103c3160e63207bd7d78aa1dbe1496300",
"signSignature":
"5030bf9be108b4a4084a32a7f35d74b893bdf4c67678b7f94b923b3cf1048d890e94e816a210e4442fe8e7bdab3ab45c1959adae14d6200cf552d3413a10900d",
"id": "12155900509392441171"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"multisignature": {
"min": 2,
"lifetime": 9,
"keysgroup": [
"+56364190bc7dd833b37450a45a4beddf1bd7408324b75bf52f85decb424a159b",
"+11364ec15a0060b0e07846a5dfa81d2f43351bf35b360dc9f780ececb6402ad4",
"+e29841ce6c5147027b52eb2551ece8c3aa62090f563093e243a978a0dccee692",
"+f079d3f68a1b0b03824b229efb0814df113f255f1cfb06f26bac205bcadb2840",
"+95c11960a7deacab27f59518f1b47b3a7f9c37819ca80e9c0fad8a39a2eb3917"
]
}
},
"signature":
"2afa46bb4563de7f56254b06c8752a4bdf76a798971b1c9644d7e74bac7e58c8d234b0650d49462b2ca9fa6cdf26c572da8cd680e8de62bd9cc14f65f97a180e",
"signSignature":
"b8d0ab01ca30cd06f792fcc3e82ad1df451f6239fb470444d026c9e5b32fc9ccee3ab9deb398119b9d23ff76c3a807d210f32310a3b4c43e7ec3d7e05e6b6203",
"id": "14759833290133825198"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"dapp": {
"category": 0,
"name": "nryO",
"description": "7qs1Iv",
"tags": "fZdhM1QGdTlJWjhSZzPsH",
"type": 0,
"link": "OzG0whsxmEda24cfdA",
"icon": "pMOY8WpXagaPdVptqR1prGPdM"
}
},
"signature":
"bb5f425e4c7aeed0f4899b22692e240e22e41756cae85113c73a200cdc607005c28d218bd29de212d4b2c65919b174ea097719341f5f023ade9c26c90d75ea05",
"signSignature":
"2597f3aa8afea57a1b8ab2328db3ee5abf315f0b367b686e50677da0ffabceee6694d9bb1c6613b7b218ee6c68ca5457261255dba185709fc44956a4eb523707",
"id": "12078587542208625234"
},
{
"type": 0,
"amount": "2312331300000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196078,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"1cc982da7c70f06b32debb6bd3032c469a3ad5444b0257745297dbccf71050f382191e797daeb707a0eaba9286917fab90c5a37c8f2f49301febecc777c1eb0c",
"id": "8974713600754318131"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"votes": [
"+2af82af1fd00f4c0e36037e124309a083769e307025c10ff29c66cac577cafec",
"+186521db6b809b250113a5bba66a1a6507251b8abba1d24f047b0984c050a1b5",
"+28cf88ac965648c238a2fabb8ac7b8fe4aba6327bb32bcc6aa291a8ce59a4c78",
"+77731ea9884dd4c684b7571b7e78b998fabbda4a66715854c40b7ee368ae446b",
"-d6124c312884182d2fd4c51a829a480cb30d00052daf257d224e62ab1969d268"
]
},
"signature":
"d0d603149cdac8ebd24d2617daca259d7cb0d7e14429421468e1a93f8c118e78ba78e0080e4b9b0d57daeefa0b973afff8cf2e984db2878730b5d868b3eabc09",
"id": "5300315452366475326"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"delegate": {
"username": "BmgeSxNgl7gWN4",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"ebc920b067e78f2350b7baceae66f4a74397912beed8ac9a8d1656fc28187b8849bbb593762b62843e7009cb15a626a7157eb3a0e6c828f69364932e8c0a2204",
"id": "14549490938474611289"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"multisignature": {
"min": 2,
"lifetime": 1,
"keysgroup": [
"+e64df51060a2ce43f91b24ae75cc83f1866f9fead2ca2420cf3df153e6368a97",
"+4ef26ed51f4b82134b16f25a2556bed98a0b3963a17c0d2f0fa87f67cc6f29fe",
"+818d34925549e0aea67f1b82190c3e288b1c66de95ce699c2f5c87f1e622012c",
"+a2eece2bf0ee74e492939ac84723646270bfefab84914a5cf68baffd9bb84858",
"+46f3ec44dbcffe28c6bcd4eb494ce24ceea51677eb67005bdd4dd3202db55251"
]
}
},
"signature":
"4c8a3bfaacfab18a7ef34ce8d7176ea2701dfd7221a1c95ecbc1cce778bbccdb7cbbe1a87b3e9e47330f1cae6665c4a44666e132aa324de9a5ab9b6a1e2b1d0c",
"id": "18066659039293493823"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196078,
"asset": {
"dapp": {
"category": 0,
"name": "y2OPqyGLuw3F5u2Sxd",
"description": "xBIt2niD",
"tags": "qQvydic4uuw61X7a7cZ6tjrUKK2C",
"type": 0,
"link": "MaRhi5E7G6EZu7dxaaE",
"icon": "To900QF"
}
},
"signature":
"a2910f485580a903e125b02198b0d9d8f2a9509bcd4e491932b2c30c06fad3d81969547f84073516ee24ce3036dbf388e63eede7e80848b555669c6d2392040b",
"id": "13459454681692221740"
},
{
"type": 0,
"amount": "2801887300000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196079,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"be08dc16b70c47f58520f93599e72ad087d323adc312fc5cf89d57938f7a098686686551a834e52180e5b07a2b7339982581871b2da69f38fdf72df93c022901",
"signSignature":
"f2367e1be7450922a72168390dc1e1dfa7e3a685bb4755938b7f0ff48c18bbda4a11ea3309aaeb2398a5b110ec341d7d0b30f0f9cf6337231936b444dd4bb502",
"id": "13907564008476426594"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"votes": [
"+6af5a4fdf2fdd10e565cd22dbc0bf942fa8c59786a29a4b3706ffe559331d636",
"+5bc0c67294e9a5be07c00fe051a50409502a62aa87032b60e737a15d58449333",
"+79d64906a7a4cf89736ad1fb1819aeb69b07982718b45b590b1102d2ee99c1cf",
"+2b0acc7ba95b1971c60f9a6da39c947fb79a1c8b359b4f054c371d40541afaac",
"-9e117730c9a4adf1f031d122635db1f84214690cd0632302103c682c2115074e"
]
},
"signature":
"f47f4b4b5b58140281e5d61a279ff4d009004114261e3ff39a8aa6119e8de6e7975bd9b49eb10aef58edd81061f395141828e5c267131add7e50a02297e64207",
"signSignature":
"95528967d585ec9a71352ce753fb5475e54c272102d6808eee4b99e6a64561806767b5bb1e5dbd7500ca46cdddecd1bab03e5507f4d70b5132afa04c7df47b0d",
"id": "408170376416400414"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"delegate": {
"username": "h9iWcquSm9iKpFw",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"e051ee9441a04d046d390e70e15eac640dbd0289a27c2e82942be648194b9684e9eb86c9ac19f50293567ab8238047abf2d04c73f52ae7ff03230016c840440c",
"signSignature":
"25f2e872b5c20445e5c8551ae0488edf3773736f401052d3689b061c418a79f9563c0b388ba2432608a67ba57cc6e8d7292550a626ad3f1a7e29e4dab631890c",
"id": "8936243264570089909"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"multisignature": {
"min": 4,
"lifetime": 30,
"keysgroup": [
"+5bf096b1964c2a8035a1836e20aa72e775d8ed2d15b13b50c170da8f49e1c13b",
"+7167b3f440be68d7811b054f90906c595ee127e26e146ca27ebf728449b9ba63",
"+c472e853cf1e706c4e3025ec0300ed1fb03df590a7bdda8a0badca6888476591",
"+7902cd178a000cb672530ff982276e1b2b94c845988ac773abd775e5fda04a4b",
"+93d29f8c7663e4aa273176bb74e35cd8bd5e09b9688b8e5f21cbac93761e4bab"
]
}
},
"signature":
"615bfc47244237b3bb6eff7f032a4ba0530cce9ce1627f488b9075672383fff45b96641daaa715da37bba6c4b09ee12d77070e8a5c1493acc833d1806946c802",
"signSignature":
"a29ce1c2f682f924a68f85083ea6934edab494a2a81ffc3aaf090ba3a9aefb692317c97a0ce7187b1bf9bbaedb71d5f440ccd986279bee280b16b2ff5efd1006",
"id": "718478589882001258"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"dapp": {
"category": 0,
"name": "0REwN",
"description": "J82zELUzEnV",
"tags": "e",
"type": 0,
"link": "kPfG6Bt",
"icon": "ium"
}
},
"signature":
"c15cc992aa2f1ac6effc00c894e98fce68ecece7bd4ac00664437ed711b8e1bf066ea433a613476767d14c85e1cab66d548fdec9fd56f96d1b112bee224c090c",
"signSignature":
"01b142ee1ffe3dd466fe863557500296dfd8313d098ca4d1897167e3138556999f91f8f73d337b53371fc643f713fead0461a0d3b2416585d3ca236144d4f40b",
"id": "6479396717400039057"
},
{
"type": 0,
"amount": "5061165300000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196079,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"b2cef4445fc63d3100bfe4b8c5a3988962378d5f05f3f31a874545341d1421f40f6bede8195fb41de4998454510a578490dcbc5a646bcea75fe459b8be1c6002",
"id": "17133129148236935159"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"votes": [
"+be4bbac72323ecc09bfe619fa112c5dcd42191f28e1f60b6a51b84a95f248941",
"+3180e1f79f626a2ebf2fc9bb4282c931becbd8858e49b370d00055a2d6b4a062",
"+d47f95719687003314535dd710180f1ff0e152773a772c625212bb2f034b854a",
"+7a9147a984e3555fad99d774a90831baba8cc2b2f4a7e06eb3f2be2f0d3cdb5f",
"-cb201cd4887eb52834a1e1a7a59c9903393e1abe2b75d61db81ad4199bef49a0"
]
},
"signature":
"ce02d218620a527f05baf1b3f125f46a0d5faefafc3bc359f0fd65511d3b406843cbee3a4d156669267d6510f870b5d359a07402f6f1695e5de4354822a6470c",
"id": "5473217291152754023"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"delegate": {
"username": "6YGNabt2vP",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"219af05289f95a6c5c920760d77afa80c750f11f221d21b6ae47942391d83aace624edc3814655cebe77ae045613c8148cbda97b3cda95ea52e19349611e7103",
"id": "4535306837758230670"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196079,
"asset": {
"dapp": {
"category": 0,
"name": "mZDJS",
"description": "O1sUrkoqguTAET3O7B",
"tags": "r2r9zWXWF3faCg",
"type": 0,
"link": "FYZZq0oT9i4UtRb3o7rLLKxQQFavCkrdgQ",
"icon": "KgpJyKuT8AxYN9JQ"
}
},
"signature":
"cb4bc3a6279b9b994ee182f3dd65628910b8e0570685797877bbb2ded9679b6b00c3a6113b034ac5bead165b78dfdc4bb71620e3f99daf871d9399758a9ba30b",
"id": "17759930910428062541"
},
{
"type": 0,
"amount": "4876278400000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196080,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"832fa468ebdad7a5accb6b16b8c82222f0a97bc00233451a89e18100dc22d9df2fc722a09549d3ef832d483c8e8c18e9765e963b5203a147c0c4b9236021cd06",
"id": "11425498570993926585"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"votes": [
"+bfabfacd8fbd8d8a8aa825c07344d627c8e5b548b3c8af0bf0c447aad509c1ca",
"+01da309703eb58d4e6fd1ba576ea37bf9b1d40eae756907c14434e3922900e13",
"+9f7744d69fad50a9f187a6bc7a2f9847aa70302cd11459a33d7278eb0cf14dea",
"+2d417477f8d4690188fa277eef6a49b0386a4c2a68643e61ed507fa14c1157d5",
"-d8e2228f3bf31ab2cd455b8d04df8f37139c725c5819b328492d6e6c7a3779fe"
]
},
"signature":
"26e5a15fc5fe2e17cee68c61c73e2ca2b8c616cfcd6ae4aa9137f32bab7617bf11ba1ca41826c45244a47a0ff273c1e1eadaf24c88aeda67ff9993597ed0800b",
"id": "912105933902813252"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"delegate": {
"username": "a4axYoN",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"aa609c506bf96cd4c179cff4dacae3574ee84a075adc8b626181d7a357fa30498ac04ee4a536848674131a7629871c7e89c3d7cf5b98fe8bb0c84e7144da890f",
"id": "13972423096514804371"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"dapp": {
"category": 0,
"name": "WRZhl8",
"description": "xpxq9w6h",
"tags": "bC1605OZ6RgRRj2",
"type": 0,
"link": "2RKLfLCm13xX2eZ4WMoWBAAig6QioF",
"icon": "Yht9kxY37iCys8FVaFgBqBlk8WG"
}
},
"signature":
"6cf050d618b6dc8b5e993de10eeba304d6f77eaf62e7893d976bcbdacaa194b89bac3c5bddb6e81a5cface98dafdc9be5b971768acaf8e5a820d460933f49706",
"id": "13519964049473247354"
},
{
"type": 0,
"amount": "7543868600000000",
"fee": "10000000",
"recipientId": "1859190791819301L",
"timestamp": 54196080,
"asset": {},
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"signature":
"ce60ee3b844d3bbd8030b842ba9568c857e6de41aa2e19322ab6314b8e66afa419752816fd17ad88a75dc8ef763de782be68cc27d3d47e0b5cd63f38de6a2d0f",
"signSignature":
"2d572dcce12b1e8acf7e46b0a40576d3408045fd4f7e432e4a1853f8092e387e322ad390e14f091176f6fd84bcb72b7011aecd9390230ea4a21db74546abc507",
"id": "6263613751669009115"
},
{
"type": 3,
"amount": "0",
"fee": "100000000",
"recipientId": "16313739661670634666L",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"votes": [
"+0b8a49bb952e5ed645cddb5fb9393c2f8a1be4f261c7623ce0ddb2b6b2a1be3e",
"+9cc4e085fe359f20c110ce5cf2ff30ffb4d6d613922e31afd572693be8e3f8ba",
"+d2133bd20300544bc4e16ba828223dd3d58955425634a2e2cd6762821f6176a2",
"+f11575b059598ffb9f0505e72041d05c685f949c4cce46c4366f50177d97dfbf",
"-cdfda7456076b9025b2964ef0679e8e1a5c3b8cd0d63345d7a05ac6faeea5f8b"
]
},
"signature":
"88c499e3dd5e10fecb16a192df9f8c81c32e9a7d2ac1f473bb076c7598cb431b14eb17423bf9493d8b112ca74b7cf1c64caa4a044cbac35f895185906f1b6107",
"signSignature":
"30dec17a7d2d0b13df25e958e66481407b87da3f35a9b8c7e93044dcb4cf13970491cf2d9b0778258865b051f8eb3b53b8e15a52d2cbdd48ed67ff2d55edec07",
"id": "15014970331019583344"
},
{
"type": 2,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"delegate": {
"username": "L4cPrZgeE",
"publicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f"
}
},
"signature":
"9e3d66ed9ba75a26b7380e09c29c38670b09233b9ca01ba93233fb0ce38e1c1fc92d66577292d2d70738d756a544878e044c3f49eb0dce22ad3c85c6211b5f09",
"signSignature":
"6ca1fe51268a786412f8f757d5fc0243f8ae00fa88812ae8501d399ed7e68326403fe68a508df4ab8ba48a98ac08d0f061ee21f5001f29cbc2f5343b0a66660f",
"id": "9014172721793470554"
},
{
"type": 4,
"amount": "0",
"fee": "3000000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"multisignature": {
"min": 5,
"lifetime": 38,
"keysgroup": [
"+617286b8de6ef7a91c7a0915a3c45ca9676216cbc8dc14bffa5e9022ea3a5683",
"+8141def6de5e8c92843d2af9589cd2568f3bb5e475dae78d334abde60682695c",
"+925e387ca6c63427391adb697273a4da8852944066ab33d50cb8e6279248427e",
"+9645504d7e06135a7a5db072aef3a6d80bb7ec8ca8cb61bc8f369faaa05587a8",
"+e1808d0e57e47bc1ffb21683c0bf98bbabe1c7e43d6bc6c2890a16d03543c100"
]
}
},
"signature":
"4a058d11726300ef0dd62941ce8f2ee861383f9448f17580826dcbef9cb62b0d953004eef3659a8b6d16bfd25b0732f93877f9b29e8828946ca849d9bb7b2d02",
"signSignature":
"ac3a9eec518b8c725aa8f8620546001f72b3036078242ab0c7639b6d6891ba4330448cc3e4f5c31516e896af4c5fa998fc2ba2673655a4cfb76168c8785c9109",
"id": "2884334432991037421"
},
{
"type": 5,
"amount": "0",
"fee": "2500000000",
"recipientId": "",
"senderPublicKey":
"c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f",
"timestamp": 54196080,
"asset": {
"dapp": {
"category": 0,
"name": "OpwYfwHdAfO4ncn7D",
"description": "Ds",
"tags": "1nkfYVcgsisKnXyn7k0",
"type": 0,
"link": "WQDusb0DgH",
"icon": "RPAFQsBIsE"
}
},
"signature":
"524afb27d284e4e71ea44de9d23f9a1cd603f37f81a55187a61ca92391dce1994d2c4a5e3f0ae8490caac66da5125a0d03f30d0775592aa02d451a72e3ed9303",
"signSignature":
"7043b795dab467e3d3239e7c379ee1b07914a8ba04e639bda406f6ed8810d75a7b4066ad5e90ef3c2030927b917e8492db59ffad017ce51878b7217b27d3a506",
"id": "7976119586785833934"
}
]
================================================
FILE: packages/lisk-transactions/package.json
================================================
{
"name": "@liskhq/lisk-transactions",
"version": "2.0.0",
"description": "Everything related to transactions according to the Lisk protocol",
"author": "Lisk Foundation , lightcurve GmbH ",
"license": "GPL-3.0",
"keywords": [
"lisk",
"blockchain"
],
"homepage": "https://github.com/LiskHQ/lisk-elements/tree/master/packages/lisk-transactions#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/LiskHQ/lisk-elements.git"
},
"bugs": {
"url": "https://github.com/LiskHQ/lisk-elements/issues"
},
"engines": {
"node": ">=8.10 <=10",
"npm": ">=5"
},
"main": "dist-node/index.js",
"scripts": {
"transpile": "tsc",
"transpile:browsertest": "tsc -p tsconfig.browsertest.json",
"browserify": "browserify ./dist-node/index.js -o ./dist-browser/index.js -s liskTransactions",
"browserify:browsertest": "browserify ./browsertest.build/test/*.js -o ./browsertest.build/browsertest.js -s liskTransactions",
"uglify": "uglifyjs -nm -o ./dist-browser/index.min.js ./dist-browser/index.js",
"uglify:browsertest": "uglifyjs -o ./browsertest.build/browsertest.min.js ./browsertest.build/browsertest.js",
"clean": "./scripts/clean.sh",
"format": "prettier --write \"*.{ts,js,json}\" \"{src,test}/**/*.{ts,js,json}\"",
"lint": "tslint --format verbose --project .",
"lint:fix": "npm run lint -- --fix",
"test": "TS_NODE_PROJECT=./test/tsconfig.json nyc mocha test/{,/**/,/**/**/}/*.ts",
"test:watch": "npm test -- --watch",
"test:watch:min": "npm run test:watch -- --reporter=min",
"test:node": "npm run build:check",
"serve:start": "http-server -p 11545 ./browsertest &",
"serve:stop": "kill $(lsof -t -i:11545) || true",
"pretest:browser": "npm run serve:stop && npm run build:browsertest && npm run serve:start",
"test:browser": "wait-on http://localhost:11545 && cypress run --config baseUrl=http://localhost:11545 --env ROOT_DIR=\"${PWD##*/}\"",
"posttest:browser": "npm run serve:stop",
"cover": "if [ -z $JENKINS_HOME ]; then npm run cover:local; else npm run cover:ci; fi",
"cover:base": "NODE_ENV=test nyc report",
"cover:local": "npm run cover:base -- --reporter=html --reporter=text",
"cover:ci": "npm run cover:base -- --reporter=text",
"build:browsertest": "npm run transpile:browsertest && npm run browserify:browsertest && npm run uglify:browsertest",
"postbuild:browsertest": "rm -r browsertest.build/src browsertest.build/test",
"prebuild:node": "rm -r dist-node/* || mkdir dist-node || true",
"build:node": "npm run transpile",
"prebuild:browser": "rm ./dist-browser/index.js ./dist-browser/index.min.js || true",
"build:browser": "npm run build:node && npm run browserify && npm run uglify",
"prebuild": "npm run prebuild:browser",
"build": "npm run build:browser",
"build:check": "node -e \"require('./dist-node')\"",
"prepublishOnly": "npm run lint && npm test && npm run build && npm run build:check"
},
"dependencies": {
"@liskhq/lisk-cryptography": "2.0.0",
"@types/node": "10.10.1",
"ajv": "6.5.3",
"ajv-merge-patch": "4.1.0",
"browserify-bignum": "1.3.0-2"
},
"devDependencies": {
"@types/chai": "4.1.5",
"@types/expect": "1.20.3",
"@types/jquery": "3.3.22",
"@types/mocha": "5.2.5",
"browserify": "16.2.2",
"chai": "4.1.2",
"cypress": "3.1.0",
"http-server": "0.11.1",
"mocha": "5.2.0",
"nyc": "13.0.1",
"prettier": "1.14.2",
"sinon": "6.2.0",
"sinon-chai": "3.2.0",
"source-map-support": "0.5.9",
"ts-node": "7.0.1",
"tsconfig-paths": "3.6.0",
"tslint": "5.11.0",
"tslint-config-prettier": "1.15.0",
"tslint-immutable": "4.7.0",
"typescript": "3.0.3",
"uglify-es": "3.3.9",
"wait-on": "3.0.1"
}
}
================================================
FILE: packages/lisk-transactions/src/0_transfer.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BYTESIZES, TRANSFER_FEE } from './constants';
import {
PartialTransaction,
TransferAsset,
TransferTransaction,
} from './transaction_types';
import {
prepareTransaction,
validateAddress,
validatePublicKey,
validateTransferAmount,
} from './utils';
const createAsset = (data?: string): TransferAsset => {
if (data && data.length > 0) {
return { data };
}
return {};
};
export interface TransferInputs {
readonly amount: string;
readonly data?: string;
readonly passphrase?: string;
readonly recipientId?: string;
readonly recipientPublicKey?: string;
readonly secondPassphrase?: string;
readonly timeOffset?: number;
}
const validateInputs = ({
amount,
recipientId,
recipientPublicKey,
data,
}: TransferInputs): void => {
if (!validateTransferAmount(amount)) {
throw new Error('Amount must be a valid number in string format.');
}
if (!recipientId && !recipientPublicKey) {
throw new Error(
'Either recipientId or recipientPublicKey must be provided.',
);
}
if (typeof recipientId !== 'undefined') {
validateAddress(recipientId);
}
if (typeof recipientPublicKey !== 'undefined') {
validatePublicKey(recipientPublicKey);
}
if (
recipientId &&
recipientPublicKey &&
recipientId !== cryptography.getAddressFromPublicKey(recipientPublicKey)
) {
throw new Error('recipientId does not match recipientPublicKey.');
}
if (data && data.length > 0) {
if (typeof data !== 'string') {
throw new Error(
'Invalid encoding in transaction data. Data must be utf-8 encoded string.',
);
}
if (data.length > BYTESIZES.DATA) {
throw new Error('Transaction data field cannot exceed 64 bytes.');
}
}
};
export const transfer = (inputs: TransferInputs): TransferTransaction => {
validateInputs(inputs);
const {
data,
amount,
recipientPublicKey,
passphrase,
secondPassphrase,
timeOffset,
} = inputs;
const recipientIdFromPublicKey = recipientPublicKey
? cryptography.getAddressFromPublicKey(recipientPublicKey)
: undefined;
const recipientId = inputs.recipientId
? inputs.recipientId
: recipientIdFromPublicKey;
const transaction: PartialTransaction = {
type: 0,
amount: amount.toString(),
fee: TRANSFER_FEE.toString(),
recipientId,
recipientPublicKey,
asset: createAsset(data),
};
return prepareTransaction(
transaction,
passphrase,
secondPassphrase,
timeOffset,
) as TransferTransaction;
};
================================================
FILE: packages/lisk-transactions/src/1_register_second_passphrase.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { SIGNATURE_FEE } from './constants';
import {
PartialTransaction,
SecondSignatureTransaction,
} from './transaction_types';
import { prepareTransaction } from './utils';
export interface SecondPassphraseInputs {
readonly passphrase?: string;
readonly secondPassphrase: string;
readonly timeOffset?: number;
}
const validateInputs = ({
secondPassphrase,
}: {
readonly secondPassphrase: string;
}): void => {
if (typeof secondPassphrase !== 'string') {
throw new Error('Please provide a secondPassphrase. Expected string.');
}
};
export const registerSecondPassphrase = (
inputs: SecondPassphraseInputs,
): SecondSignatureTransaction => {
validateInputs(inputs);
const { passphrase, secondPassphrase, timeOffset } = inputs;
const { publicKey } = cryptography.getKeys(secondPassphrase);
const transaction: PartialTransaction = {
type: 1,
fee: SIGNATURE_FEE.toString(),
asset: {
signature: {
publicKey,
},
},
};
return prepareTransaction(
transaction,
passphrase,
secondPassphrase,
timeOffset,
) as SecondSignatureTransaction;
};
================================================
FILE: packages/lisk-transactions/src/2_register_delegate.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { DELEGATE_FEE, USERNAME_MAX_LENGTH } from './constants';
import { DelegateTransaction, PartialTransaction } from './transaction_types';
import { prepareTransaction } from './utils';
export interface RegisterDelegateInputs {
readonly passphrase?: string;
readonly secondPassphrase?: string;
readonly timeOffset?: number;
readonly username: string;
}
const validateInputs = ({ username }: { readonly username: string }): void => {
if (!username || typeof username !== 'string') {
throw new Error('Please provide a username. Expected string.');
}
if (username.length > USERNAME_MAX_LENGTH) {
throw new Error(
`Username length does not match requirements. Expected to be no more than ${USERNAME_MAX_LENGTH} characters.`,
);
}
};
export const registerDelegate = (
inputs: RegisterDelegateInputs,
): DelegateTransaction => {
validateInputs(inputs);
const { passphrase, secondPassphrase, timeOffset, username } = inputs;
const transaction: PartialTransaction = {
type: 2,
fee: DELEGATE_FEE.toString(),
asset: {
delegate: {
username,
},
},
};
return prepareTransaction(
transaction,
passphrase,
secondPassphrase,
timeOffset,
) as DelegateTransaction;
};
================================================
FILE: packages/lisk-transactions/src/3_cast_votes.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { VOTE_FEE } from './constants';
import { PartialTransaction, VoteTransaction } from './transaction_types';
import {
prepareTransaction,
prependMinusToPublicKeys,
prependPlusToPublicKeys,
validatePublicKeys,
} from './utils';
export interface CastVoteInputs {
readonly passphrase?: string;
readonly secondPassphrase?: string;
readonly timeOffset?: number;
readonly unvotes?: ReadonlyArray;
readonly votes?: ReadonlyArray;
}
interface VotesObject {
readonly unvotes?: ReadonlyArray;
readonly votes?: ReadonlyArray;
}
const validateInputs = ({ votes = [], unvotes = [] }: VotesObject): void => {
if (!Array.isArray(votes)) {
throw new Error(
'Please provide a valid votes value. Expected an array if present.',
);
}
if (!Array.isArray(unvotes)) {
throw new Error(
'Please provide a valid unvotes value. Expected an array if present.',
);
}
validatePublicKeys([...votes, ...unvotes]);
};
export const castVotes = (inputs: CastVoteInputs): VoteTransaction => {
validateInputs(inputs);
const {
passphrase,
secondPassphrase,
timeOffset,
votes = [],
unvotes = [],
} = inputs;
const recipientId = passphrase
? cryptography.getAddressAndPublicKeyFromPassphrase(passphrase).address
: '';
const plusPrependedVotes = prependPlusToPublicKeys(votes);
const minusPrependedUnvotes = prependMinusToPublicKeys(unvotes);
const allVotes: ReadonlyArray = [
...plusPrependedVotes,
...minusPrependedUnvotes,
];
const transaction: PartialTransaction = {
type: 3,
fee: VOTE_FEE.toString(),
recipientId,
asset: {
votes: allVotes,
},
};
return prepareTransaction(
transaction,
passphrase,
secondPassphrase,
timeOffset,
) as VoteTransaction;
};
================================================
FILE: packages/lisk-transactions/src/4_register_multisignature_account.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import {
MULTISIGNATURE_FEE,
MULTISIGNATURE_MAX_KEYSGROUP,
MULTISIGNATURE_MAX_LIFETIME,
MULTISIGNATURE_MIN_KEYSGROUP,
MULTISIGNATURE_MIN_LIFETIME,
} from './constants';
import {
MultiSignatureTransaction,
PartialTransaction,
} from './transaction_types';
import {
isValidInteger,
prepareTransaction,
prependPlusToPublicKeys,
validateKeysgroup,
} from './utils';
export interface RegisterMultisignatureInputs {
readonly keysgroup: ReadonlyArray;
readonly lifetime: number;
readonly minimum: number;
readonly passphrase?: string;
readonly secondPassphrase?: string;
readonly timeOffset?: number;
}
const validateInputs = ({
keysgroup,
lifetime,
minimum,
}: {
readonly keysgroup: ReadonlyArray;
readonly lifetime: number;
readonly minimum: number;
}): void => {
if (
!isValidInteger(lifetime) ||
lifetime < MULTISIGNATURE_MIN_LIFETIME ||
lifetime > MULTISIGNATURE_MAX_LIFETIME
) {
throw new Error(
`Please provide a valid lifetime value. Expected integer between ${MULTISIGNATURE_MIN_LIFETIME} and ${MULTISIGNATURE_MAX_LIFETIME}.`,
);
}
if (
!isValidInteger(minimum) ||
minimum < MULTISIGNATURE_MIN_KEYSGROUP ||
minimum > MULTISIGNATURE_MAX_KEYSGROUP
) {
throw new Error(
`Please provide a valid minimum value. Expected integer between ${MULTISIGNATURE_MIN_KEYSGROUP} and ${MULTISIGNATURE_MAX_KEYSGROUP}.`,
);
}
if (keysgroup.length < minimum) {
throw new Error(
'Minimum number of signatures is larger than the number of keys in the keysgroup.',
);
}
validateKeysgroup(keysgroup);
};
export const registerMultisignature = (
inputs: RegisterMultisignatureInputs,
): MultiSignatureTransaction => {
validateInputs(inputs);
const {
keysgroup,
lifetime,
minimum,
passphrase,
secondPassphrase,
timeOffset,
} = inputs;
const plusPrependedKeysgroup = prependPlusToPublicKeys(keysgroup);
const keygroupFees = plusPrependedKeysgroup.length + 1;
const transaction: PartialTransaction = {
type: 4,
fee: (MULTISIGNATURE_FEE * keygroupFees).toString(),
asset: {
multisignature: {
min: minimum,
lifetime,
keysgroup: plusPrependedKeysgroup,
},
},
};
return prepareTransaction(
transaction,
passphrase,
secondPassphrase,
timeOffset,
) as MultiSignatureTransaction;
};
================================================
FILE: packages/lisk-transactions/src/5_create_dapp.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { DAPP_FEE } from './constants';
import { DappTransaction, PartialTransaction } from './transaction_types';
import { isValidInteger, prepareTransaction } from './utils';
export interface DappOptions {
readonly category: number;
readonly description: string;
readonly icon: string;
readonly link: string;
readonly name: string;
readonly tags: string;
readonly type: number;
}
export interface DappInputs {
readonly options: DappOptions;
readonly passphrase?: string;
readonly secondPassphrase?: string;
readonly timeOffset?: number;
}
const validateInputs = ({ options }: DappInputs): void => {
if (typeof options !== 'object') {
throw new Error('Options must be an object.');
}
const { category, name, type, link, description, tags, icon } = options;
if (!isValidInteger(category)) {
throw new Error('Dapp category must be an integer.');
}
if (typeof name !== 'string') {
throw new Error('Dapp name must be a string.');
}
if (!isValidInteger(type)) {
throw new Error('Dapp type must be an integer.');
}
if (typeof link !== 'string') {
throw new Error('Dapp link must be a string.');
}
if (typeof description !== 'undefined' && typeof description !== 'string') {
throw new Error('Dapp description must be a string if provided.');
}
if (typeof tags !== 'undefined' && typeof tags !== 'string') {
throw new Error('Dapp tags must be a string if provided.');
}
if (typeof icon !== 'undefined' && typeof icon !== 'string') {
throw new Error('Dapp icon must be a string if provided.');
}
};
export const createDapp = (inputs: DappInputs): DappTransaction => {
validateInputs(inputs);
const { passphrase, secondPassphrase, timeOffset, options } = inputs;
const transaction: PartialTransaction = {
type: 5,
fee: DAPP_FEE.toString(),
asset: {
dapp: {
category: options.category,
name: options.name,
description: options.description,
tags: options.tags,
type: options.type,
link: options.link,
icon: options.icon,
},
},
};
return prepareTransaction(
transaction,
passphrase,
secondPassphrase,
timeOffset,
) as DappTransaction;
};
================================================
FILE: packages/lisk-transactions/src/constants.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
/* tslint:disable:no-magic-numbers */
export const FIXED_POINT = 10 ** 8;
export const TRANSFER_FEE = FIXED_POINT * 0.1;
export const IN_TRANSFER_FEE = FIXED_POINT * 0.1;
export const OUT_TRANSFER_FEE = FIXED_POINT * 0.1;
export const SIGNATURE_FEE = FIXED_POINT * 5;
export const DELEGATE_FEE = FIXED_POINT * 25;
export const VOTE_FEE = FIXED_POINT * 1;
export const MULTISIGNATURE_FEE = FIXED_POINT * 5;
export const MULTISIGNATURE_MAX_LIFETIME = 72;
export const MULTISIGNATURE_MIN_LIFETIME = 1;
export const MULTISIGNATURE_MAX_KEYSGROUP = 15;
export const MULTISIGNATURE_MIN_KEYSGROUP = 1;
export const DAPP_FEE = FIXED_POINT * 25;
export const USERNAME_MAX_LENGTH = 20;
export const BYTESIZES = {
TYPE: 1,
TIMESTAMP: 4,
MULTISIGNATURE_PUBLICKEY: 32,
RECIPIENT_ID: 8,
AMOUNT: 8,
SIGNATURE_TRANSACTION: 64,
SECOND_SIGNATURE_TRANSACTION: 64,
DATA: 64,
};
export const EPOCH_TIME = new Date(Date.UTC(2016, 4, 24, 17, 0, 0, 0));
export const EPOCH_TIME_MILLISECONDS = EPOCH_TIME.getTime();
const MS_FACTOR = 1000;
export const EPOCH_TIME_SECONDS = Math.floor(EPOCH_TIME.getTime() / MS_FACTOR);
// Largest possible number which can be stored in eight bytes.
// Derived from bignum.fromBuffer(Buffer.from(new Array(8).fill(255))).
const MAX_EIGHT_BYTE_NUMBER = '18446744073709551615';
export const MAX_ADDRESS_NUMBER = MAX_EIGHT_BYTE_NUMBER;
export const MAX_TRANSACTION_ID = MAX_EIGHT_BYTE_NUMBER;
// Largest possible amount. Maximum value for PostgreSQL bigint.
export const MAX_TRANSACTION_AMOUNT = '9223372036854775807';
================================================
FILE: packages/lisk-transactions/src/create_signature_object.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BaseTransaction } from './transaction_types';
import { multiSignTransaction, verifyTransaction } from './utils';
export interface SignatureObject {
readonly publicKey: string;
readonly signature: string;
readonly transactionId: string;
}
export const createSignatureObject = (
transaction: BaseTransaction,
passphrase: string,
): SignatureObject => {
if (!verifyTransaction(transaction)) {
throw new Error('Invalid transaction.');
}
if (!transaction.id) {
throw new Error('Transaction ID is required to create a signature object.');
}
const { publicKey } = cryptography.getPrivateAndPublicKeyFromPassphrase(
passphrase,
);
return {
transactionId: transaction.id,
publicKey,
signature: multiSignTransaction(transaction, passphrase),
};
};
================================================
FILE: packages/lisk-transactions/src/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { transfer } from './0_transfer';
import { registerSecondPassphrase } from './1_register_second_passphrase';
import { registerDelegate } from './2_register_delegate';
import { castVotes } from './3_cast_votes';
import { registerMultisignature } from './4_register_multisignature_account';
import { createDapp } from './5_create_dapp';
import * as constants from './constants';
import { createSignatureObject } from './create_signature_object';
import * as utils from './utils';
export {
transfer,
registerSecondPassphrase,
registerDelegate,
castVotes,
registerMultisignature,
createSignatureObject,
createDapp,
utils,
constants,
};
================================================
FILE: packages/lisk-transactions/src/transaction_types.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export interface BaseTransaction {
readonly amount: string;
readonly asset: TransactionAsset;
readonly fee: string;
readonly id?: string;
readonly recipientId: string | null;
readonly recipientPublicKey?: string | null;
readonly requesterPublicKey?: string;
readonly senderId?: string;
readonly senderPublicKey: string;
readonly signature?: string;
readonly signatures?: ReadonlyArray;
readonly signSignature?: string;
readonly timestamp: number;
readonly type: number;
}
type Partial = { [P in keyof T]?: T[P] };
export type PartialTransaction = Partial;
export type TransactionAsset =
| TransferAsset
| SecondSignatureAsset
| DelegateAsset
| VoteAsset
| MultiSignatureAsset
| DappAsset
| InTransferAsset
| OutTransferAsset;
export interface TransferTransaction extends BaseTransaction {
readonly asset: TransferAsset;
}
export interface TransferAsset {
readonly data?: string;
}
export interface SecondSignatureTransaction extends BaseTransaction {
readonly asset: SecondSignatureAsset;
}
export interface SecondSignatureAsset {
readonly signature: {
readonly publicKey: string;
};
}
export interface DelegateTransaction extends BaseTransaction {
readonly asset: DelegateAsset;
}
export interface DelegateAsset {
readonly delegate: {
readonly username: string;
};
}
export interface VoteTransaction extends BaseTransaction {
readonly asset: VoteAsset;
}
export interface VoteAsset {
readonly votes: ReadonlyArray;
}
export interface MultiSignatureTransaction extends BaseTransaction {
readonly asset: MultiSignatureAsset;
}
export interface MultiSignatureAsset {
readonly multisignature: {
readonly keysgroup: ReadonlyArray;
readonly lifetime: number;
readonly min: number;
};
}
export interface DappTransaction extends BaseTransaction {
readonly asset: DappAsset;
}
export interface DappAsset {
readonly dapp: {
readonly category: number;
readonly description?: string;
readonly icon?: string;
readonly link: string;
readonly name: string;
readonly tags?: string;
readonly type: number;
};
}
export interface InTransferTransaction extends BaseTransaction {
readonly asset: InTransferAsset;
}
export interface InTransferAsset {
readonly inTransfer: {
readonly dappId: string;
};
}
export interface OutTransferTransaction extends BaseTransaction {
readonly asset: OutTransferAsset;
}
export interface OutTransferAsset {
readonly outTransfer: {
readonly dappId: string;
readonly transactionId: string;
};
}
================================================
FILE: packages/lisk-transactions/src/utils/format.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import BigNum from 'browserify-bignum';
import { FIXED_POINT } from '../constants';
import { isGreaterThanMaxTransactionAmount } from './validation';
const BASE_10 = 10;
const LISK_MAX_DECIMAL_POINTS = 8;
const getDecimalPlaces = (amount: string): number =>
(amount.split('.')[1] || '').length;
export const convertBeddowsToLSK = (beddowsAmount?: string): string => {
if (typeof beddowsAmount !== 'string') {
throw new Error('Cannot convert non-string amount');
}
if (getDecimalPlaces(beddowsAmount)) {
throw new Error('Beddows amount should not have decimal points');
}
const beddowsAmountBigNum = new BigNum(beddowsAmount);
if (isGreaterThanMaxTransactionAmount(beddowsAmountBigNum)) {
throw new Error('Beddows amount out of range');
}
const lskAmountBigNum = beddowsAmountBigNum.div(FIXED_POINT);
return lskAmountBigNum.toString(BASE_10);
};
export const convertLSKToBeddows = (lskAmount?: string): string => {
if (typeof lskAmount !== 'string') {
throw new Error('Cannot convert non-string amount');
}
if (getDecimalPlaces(lskAmount) > LISK_MAX_DECIMAL_POINTS) {
throw new Error('LSK amount has too many decimal points');
}
const lskAmountBigNum = new BigNum(lskAmount);
const beddowsAmountBigNum = lskAmountBigNum.mul(FIXED_POINT);
if (isGreaterThanMaxTransactionAmount(beddowsAmountBigNum)) {
throw new Error('LSK amount out of range');
}
return beddowsAmountBigNum.toString();
};
export const prependPlusToPublicKeys = (
publicKeys: ReadonlyArray,
): ReadonlyArray => publicKeys.map(publicKey => `+${publicKey}`);
export const prependMinusToPublicKeys = (
publicKeys: ReadonlyArray,
): ReadonlyArray => publicKeys.map(publicKey => `-${publicKey}`);
================================================
FILE: packages/lisk-transactions/src/utils/get_address_and_public_key_from_recipient_data.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
interface RecipientIdAndPublicKey {
readonly recipientId: string;
readonly recipientPublicKey?: string;
}
export const getAddressAndPublicKeyFromRecipientData = ({
recipientId,
recipientPublicKey,
}: RecipientIdAndPublicKey): {
readonly address: string;
readonly publicKey?: string;
} => {
if (recipientId && recipientPublicKey) {
const addressFromPublicKey = cryptography.getAddressFromPublicKey(
recipientPublicKey,
);
if (recipientId === addressFromPublicKey) {
return { address: recipientId, publicKey: recipientPublicKey };
}
throw new Error(
'Could not create transaction: recipientId does not match recipientPublicKey.',
);
}
if (!recipientId && recipientPublicKey) {
const addressFromPublicKey = cryptography.getAddressFromPublicKey(
recipientPublicKey,
);
return { address: addressFromPublicKey, publicKey: recipientPublicKey };
}
return { address: recipientId, publicKey: undefined };
};
================================================
FILE: packages/lisk-transactions/src/utils/get_transaction_bytes.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import BigNum from 'browserify-bignum';
import { BYTESIZES, MAX_TRANSACTION_AMOUNT } from '../constants';
import {
BaseTransaction,
DappAsset,
DelegateAsset,
InTransferAsset,
MultiSignatureAsset,
OutTransferAsset,
PartialTransaction,
SecondSignatureAsset,
TransactionAsset,
TransferAsset,
TransferTransaction,
VoteAsset,
} from '../transaction_types';
export const isValidValue = (value: unknown): boolean => {
if (value === undefined) {
return false;
}
if (typeof value === 'number' && Number.isNaN(value)) {
return false;
}
if (value === false) {
return false;
}
return true;
};
export const checkRequiredFields = (
requiredFields: ReadonlyArray,
data: { readonly [key: string]: unknown },
): boolean => {
const dataFields = Object.keys(data);
requiredFields.forEach(parameter => {
if (!dataFields.includes(parameter) || !isValidValue(data[parameter])) {
throw new Error(`${parameter} is a required parameter.`);
}
});
return true;
};
export const getAssetDataForTransferTransaction = (
asset: TransactionAsset,
): Buffer => {
const { data } = asset as TransferAsset;
return data ? Buffer.from(data, 'utf8') : Buffer.alloc(0);
};
export const getAssetDataForRegisterSecondSignatureTransaction = (
asset: TransactionAsset,
): Buffer => {
const { signature } = asset as SecondSignatureAsset;
checkRequiredFields(['publicKey'], signature);
const { publicKey } = signature;
return cryptography.hexToBuffer(publicKey);
};
export const getAssetDataForRegisterDelegateTransaction = (
asset: TransactionAsset,
): Buffer => {
const { delegate } = asset as DelegateAsset;
checkRequiredFields(['username'], delegate);
const { username } = delegate;
return Buffer.from(username, 'utf8');
};
export const getAssetDataForCastVotesTransaction = (
asset: TransactionAsset,
): Buffer => {
const { votes } = asset as VoteAsset;
if (!Array.isArray(votes)) {
throw new Error('votes parameter must be an Array.');
}
return Buffer.from(votes.join(''), 'utf8');
};
export const getAssetDataForRegisterMultisignatureAccountTransaction = (
asset: TransactionAsset,
): Buffer => {
const { multisignature } = asset as MultiSignatureAsset;
checkRequiredFields(['min', 'lifetime', 'keysgroup'], multisignature);
const { min, lifetime, keysgroup } = multisignature;
const minBuffer = Buffer.alloc(1, min);
const lifetimeBuffer = Buffer.alloc(1, lifetime);
const keysgroupBuffer = Buffer.from(keysgroup.join(''), 'utf8');
return Buffer.concat([minBuffer, lifetimeBuffer, keysgroupBuffer]);
};
const DAPP_TYPE_LENGTH = 4;
const DAPP_CATEGORY_LENGTH = 4;
export const getAssetDataForCreateDappTransaction = (
asset: TransactionAsset,
): Buffer => {
const { dapp } = asset as DappAsset;
checkRequiredFields(['name', 'link', 'type', 'category'], dapp);
const { name, description, tags, link, icon, type, category } = dapp;
const nameBuffer = Buffer.from(name, 'utf8');
const linkBuffer = Buffer.from(link, 'utf8');
const typeBuffer = Buffer.alloc(DAPP_TYPE_LENGTH);
typeBuffer.writeIntLE(type, 0, DAPP_TYPE_LENGTH);
const categoryBuffer = Buffer.alloc(DAPP_CATEGORY_LENGTH);
categoryBuffer.writeIntLE(category, 0, DAPP_CATEGORY_LENGTH);
const descriptionBuffer = description
? Buffer.from(description, 'utf8')
: Buffer.alloc(0);
const tagsBuffer = tags ? Buffer.from(tags, 'utf8') : Buffer.alloc(0);
const iconBuffer = icon ? Buffer.from(icon, 'utf8') : Buffer.alloc(0);
return Buffer.concat([
nameBuffer,
descriptionBuffer,
tagsBuffer,
linkBuffer,
iconBuffer,
typeBuffer,
categoryBuffer,
]);
};
export const getAssetDataForTransferIntoDappTransaction = (
asset: TransactionAsset,
): Buffer => {
const { inTransfer } = asset as InTransferAsset;
checkRequiredFields(['dappId'], inTransfer);
const { dappId } = inTransfer;
return Buffer.from(dappId, 'utf8');
};
export const getAssetDataForTransferOutOfDappTransaction = (
asset: TransactionAsset,
): Buffer => {
const { outTransfer } = asset as OutTransferAsset;
checkRequiredFields(['dappId', 'transactionId'], outTransfer);
const { dappId, transactionId } = outTransfer;
const outAppIdBuffer = Buffer.from(dappId, 'utf8');
const outTransactionIdBuffer = Buffer.from(transactionId, 'utf8');
return Buffer.concat([outAppIdBuffer, outTransactionIdBuffer]);
};
const transactionTypeAssetGetBytesMap: {
readonly [type: number]: (asset: TransactionAsset) => Buffer;
} = {
0: getAssetDataForTransferTransaction,
1: getAssetDataForRegisterSecondSignatureTransaction,
2: getAssetDataForRegisterDelegateTransaction,
3: getAssetDataForCastVotesTransaction,
4: getAssetDataForRegisterMultisignatureAccountTransaction,
5: getAssetDataForCreateDappTransaction,
6: getAssetDataForTransferIntoDappTransaction,
7: getAssetDataForTransferOutOfDappTransaction,
};
export const getAssetBytes = (transaction: BaseTransaction): Buffer =>
transactionTypeAssetGetBytesMap[transaction.type](transaction.asset);
const REQUIRED_TRANSACTION_PARAMETERS: ReadonlyArray = [
'type',
'timestamp',
'senderPublicKey',
'amount',
];
export const checkTransaction = (transaction: PartialTransaction): boolean => {
checkRequiredFields(REQUIRED_TRANSACTION_PARAMETERS, transaction);
const {
asset: { data },
} = transaction as TransferTransaction;
if (data && data.length > BYTESIZES.DATA) {
throw new Error(
`Transaction asset data exceeds size of ${BYTESIZES.DATA}.`,
);
}
return true;
};
export const getTransactionBytes = (transaction: BaseTransaction): Buffer => {
checkTransaction(transaction);
const {
type,
timestamp,
requesterPublicKey,
senderPublicKey,
recipientId,
amount,
signature,
signSignature,
} = transaction;
const transactionType = Buffer.alloc(BYTESIZES.TYPE, type);
const transactionTimestamp = Buffer.alloc(BYTESIZES.TIMESTAMP);
transactionTimestamp.writeIntLE(timestamp, 0, BYTESIZES.TIMESTAMP);
const transactionSenderPublicKey = cryptography.hexToBuffer(senderPublicKey);
const transactionRequesterPublicKey = requesterPublicKey
? cryptography.hexToBuffer(requesterPublicKey)
: Buffer.alloc(0);
const transactionRecipientID = recipientId
? cryptography.bigNumberToBuffer(
recipientId.slice(0, -1),
BYTESIZES.RECIPIENT_ID,
)
: Buffer.alloc(BYTESIZES.RECIPIENT_ID);
const amountBigNum = new BigNum(amount);
if (amountBigNum.lt(0)) {
throw new Error('Transaction amount must not be negative.');
}
// BUG in browserify-bignum prevents us using `.gt` directly.
// See https://github.com/bored-engineer/browserify-bignum/pull/2
if (amountBigNum.gte(new BigNum(MAX_TRANSACTION_AMOUNT).add(1))) {
throw new Error('Transaction amount is too large.');
}
const transactionAmount = amountBigNum.toBuffer({
endian: 'little',
size: BYTESIZES.AMOUNT,
});
const transactionAssetData = getAssetBytes(transaction);
const transactionSignature = signature
? cryptography.hexToBuffer(signature)
: Buffer.alloc(0);
const transactionSecondSignature = signSignature
? cryptography.hexToBuffer(signSignature)
: Buffer.alloc(0);
return Buffer.concat([
transactionType,
transactionTimestamp,
transactionSenderPublicKey,
transactionRequesterPublicKey,
transactionRecipientID,
transactionAmount,
transactionAssetData,
transactionSignature,
transactionSecondSignature,
]);
};
================================================
FILE: packages/lisk-transactions/src/utils/get_transaction_hash.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BaseTransaction } from '../transaction_types';
import { getTransactionBytes } from './get_transaction_bytes';
export const getTransactionHash = (transaction: BaseTransaction): Buffer => {
const bytes = getTransactionBytes(transaction);
return cryptography.hash(bytes);
};
================================================
FILE: packages/lisk-transactions/src/utils/get_transaction_id.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BaseTransaction } from '../transaction_types';
import { getTransactionBytes } from './get_transaction_bytes';
export const getTransactionId = (transaction: BaseTransaction): string => {
const transactionBytes = getTransactionBytes(transaction);
const transactionHash = cryptography.hash(transactionBytes);
const bufferFromFirstEntriesReversed = cryptography.getFirstEightBytesReversed(
transactionHash,
);
const firstEntriesToNumber = cryptography.bufferToBigNumberString(
bufferFromFirstEntriesReversed,
);
return firstEntriesToNumber;
};
================================================
FILE: packages/lisk-transactions/src/utils/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export { getTransactionBytes } from './get_transaction_bytes';
export { getTransactionHash } from './get_transaction_hash';
export { getTransactionId } from './get_transaction_id';
export {
convertBeddowsToLSK,
convertLSKToBeddows,
prependPlusToPublicKeys,
prependMinusToPublicKeys,
} from './format';
export { prepareTransaction } from './prepare_transaction';
export {
signTransaction,
multiSignTransaction,
verifyTransaction,
} from './sign_and_verify';
export { signRawTransaction } from './sign_raw_transaction';
export { getTimeFromBlockchainEpoch, getTimeWithOffset } from './time';
export {
checkPublicKeysForDuplicates,
validatePublicKey,
validatePublicKeys,
validateKeysgroup,
validateAddress,
validateAmount,
validateTransferAmount,
validateFee,
isValidInteger,
validateTransaction,
} from './validation';
================================================
FILE: packages/lisk-transactions/src/utils/prepare_transaction.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BaseTransaction, PartialTransaction } from '../transaction_types';
import { getTransactionId } from './get_transaction_id';
import { signTransaction } from './sign_and_verify';
import { getTimeWithOffset } from './time';
const secondSignTransaction = (
transactionObject: BaseTransaction,
secondPassphrase: string,
): BaseTransaction => ({
...transactionObject,
signSignature: signTransaction(transactionObject, secondPassphrase),
});
const validTransaction = (
partial: PartialTransaction,
): partial is BaseTransaction => partial.type !== undefined;
export const prepareTransaction = (
partialTransaction: PartialTransaction,
passphrase?: string,
secondPassphrase?: string,
timeOffset?: number,
): BaseTransaction => {
const senderPublicKey = passphrase
? cryptography.getKeys(passphrase).publicKey
: undefined;
const timestamp = getTimeWithOffset(timeOffset);
const transaction = {
amount: '0',
recipientId: '',
senderPublicKey,
timestamp,
...partialTransaction,
};
if (!validTransaction(transaction)) {
throw new Error('Invalid transaction to process');
}
if (!passphrase) {
return transaction;
}
const singleSignedTransaction = {
...transaction,
signature: signTransaction(transaction, passphrase),
};
const signedTransaction =
typeof secondPassphrase === 'string' && transaction.type !== 1
? secondSignTransaction(singleSignedTransaction, secondPassphrase)
: singleSignedTransaction;
const transactionWithId = {
...signedTransaction,
id: getTransactionId(signedTransaction),
};
return transactionWithId;
};
================================================
FILE: packages/lisk-transactions/src/utils/sign_and_verify.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BaseTransaction } from '../transaction_types';
import { getTransactionHash } from './get_transaction_hash';
export const signTransaction = (
transaction: BaseTransaction,
passphrase: string,
): string => {
const transactionHash = getTransactionHash(transaction);
return cryptography.signData(transactionHash, passphrase);
};
export const multiSignTransaction = (
transaction: BaseTransaction,
passphrase: string,
): string => {
const { signature, signSignature, ...transactionToSign } = transaction;
const transactionHash = getTransactionHash(transactionToSign);
return cryptography.signData(transactionHash, passphrase);
};
export const verifyTransaction = (
transaction: BaseTransaction,
secondPublicKey?: string,
): boolean => {
if (!transaction.signature) {
throw new Error('Cannot verify transaction without signature.');
}
if (!!transaction.signSignature && !secondPublicKey) {
throw new Error('Cannot verify signSignature without secondPublicKey.');
}
const {
signature,
signSignature,
...transactionWithoutSignatures
} = transaction;
const transactionWithoutSignature = !!transaction.signSignature
? {
...transactionWithoutSignatures,
signature,
}
: transactionWithoutSignatures;
const transactionHash = getTransactionHash(transactionWithoutSignature);
const publicKey =
!!transaction.signSignature && secondPublicKey
? secondPublicKey
: transaction.senderPublicKey;
const lastSignature = transaction.signSignature
? transaction.signSignature
: transaction.signature;
const verified = cryptography.verifyData(
transactionHash,
lastSignature,
publicKey,
);
return !!transaction.signSignature
? verified && verifyTransaction(transactionWithoutSignature)
: verified;
};
================================================
FILE: packages/lisk-transactions/src/utils/sign_raw_transaction.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { BaseTransaction, PartialTransaction } from '../transaction_types';
import { prepareTransaction } from './prepare_transaction';
import { getTimeWithOffset } from './time';
interface SignRawTransactionInput {
readonly passphrase: string;
readonly secondPassphrase?: string;
readonly timeOffset?: number;
readonly transaction: PartialTransaction;
}
export const signRawTransaction = ({
transaction,
passphrase,
secondPassphrase,
timeOffset,
}: SignRawTransactionInput): BaseTransaction => {
const {
publicKey,
address,
} = cryptography.getAddressAndPublicKeyFromPassphrase(passphrase);
const senderSecondPublicKey = secondPassphrase
? cryptography.getPrivateAndPublicKeyFromPassphrase(secondPassphrase)
.publicKey
: undefined;
const propertiesToAdd = {
senderPublicKey: publicKey,
senderSecondPublicKey,
senderId: address,
timestamp: getTimeWithOffset(timeOffset),
};
const transactionWithProperties = {
...transaction,
...propertiesToAdd,
};
return prepareTransaction(
transactionWithProperties,
passphrase,
secondPassphrase,
);
};
================================================
FILE: packages/lisk-transactions/src/utils/time.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { EPOCH_TIME_MILLISECONDS } from '../constants';
const MS_TIME = 1000;
export const getTimeFromBlockchainEpoch = (givenTimestamp?: number): number => {
const startingPoint = givenTimestamp || new Date().getTime();
const blockchainInitialTime = EPOCH_TIME_MILLISECONDS;
return Math.floor((startingPoint - blockchainInitialTime) / MS_TIME);
};
export const getTimeWithOffset = (offset?: number): number => {
const now = new Date().getTime();
const timeWithOffset = offset ? now + offset * MS_TIME : now;
return getTimeFromBlockchainEpoch(timeWithOffset);
};
================================================
FILE: packages/lisk-transactions/src/utils/validation/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export {
checkPublicKeysForDuplicates,
validatePublicKey,
validatePublicKeys,
validateKeysgroup,
validateAddress,
validateAmount,
validateTransferAmount,
validateFee,
isValidInteger,
isGreaterThanMaxTransactionAmount,
isGreaterThanZero,
} from './validation';
export { validateTransaction } from './validate_transaction';
================================================
FILE: packages/lisk-transactions/src/utils/validation/schema.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
export const baseTransaction = {
$id: 'lisk/base-transaction',
type: 'object',
required: [
'id',
'type',
'amount',
'fee',
'senderPublicKey',
'recipientId',
'timestamp',
'asset',
'signature',
],
properties: {
id: {
type: 'string',
format: 'id',
},
amount: {
type: 'string',
format: 'amount',
},
fee: {
type: 'string',
format: 'fee',
},
type: {
type: 'integer',
minimum: 0,
maximum: 7,
},
timestamp: {
type: 'integer',
minimum: 0,
maximum: 2147483647,
},
senderId: {
type: 'string',
format: 'address',
},
senderPublicKey: {
type: 'string',
format: 'publicKey',
},
senderSecondPublicKey: {
type: 'string',
format: 'publicKey',
},
recipientId: {
type: 'string',
},
recipientPublicKey: {
type: ['string', 'null'],
format: 'publicKey',
},
signature: {
type: 'string',
format: 'signature',
},
signSignature: {
type: 'string',
format: 'signature',
},
signatures: {
type: 'array',
uniqueItems: true,
items: {
type: 'string',
format: 'signature',
},
},
asset: {
type: 'object',
},
},
};
export const transferTransaction = {
$merge: {
source: { $ref: 'lisk/base-transaction' },
with: {
properties: {
recipientId: {
format: 'address',
},
amount: {
format: 'transferAmount',
},
asset: {
type: 'object',
properties: {
data: {
type: 'string',
maxLength: 64,
},
},
},
},
},
},
};
export const signatureTransaction = {
$merge: {
source: { $ref: 'lisk/base-transaction' },
with: {
properties: {
asset: {
type: 'object',
required: ['signature'],
properties: {
signature: {
type: 'object',
required: ['publicKey'],
properties: {
publicKey: {
type: 'string',
format: 'publicKey',
},
},
},
},
},
},
},
},
};
export const delegateTransaction = {
$merge: {
source: { $ref: 'lisk/base-transaction' },
with: {
properties: {
asset: {
type: 'object',
required: ['delegate'],
properties: {
delegate: {
type: 'object',
required: ['username'],
properties: {
username: {
type: 'string',
maxLength: 20,
},
},
},
},
},
},
},
},
};
export const voteTransaction = {
$merge: {
source: { $ref: 'lisk/base-transaction' },
with: {
properties: {
asset: {
type: 'object',
required: ['votes'],
properties: {
votes: {
type: 'array',
uniqueSignedPublicKeys: true,
minItems: 1,
maxItems: 33,
items: {
type: 'string',
format: 'signedPublicKey',
},
},
},
},
},
},
},
};
export const multiTransaction = {
$merge: {
source: { $ref: 'lisk/base-transaction' },
with: {
properties: {
asset: {
type: 'object',
required: ['multisignature'],
properties: {
multisignature: {
type: 'object',
required: ['min', 'lifetime', 'keysgroup'],
properties: {
min: {
type: 'integer',
minimum: 1,
maximum: 15,
},
lifetime: {
type: 'integer',
minimum: 1,
maximum: 72,
},
keysgroup: {
type: 'array',
uniqueItems: true,
minItems: 1,
maxItems: 15,
items: {
type: 'string',
format: 'additionPublicKey',
},
},
},
},
},
},
},
},
},
};
export const dappTransaction = {
$merge: {
source: { $ref: 'lisk/base-transaction' },
with: {
properties: {
asset: {
type: 'object',
required: ['dapp'],
properties: {
dapp: {
type: 'object',
required: ['name', 'type', 'category', 'link'],
properties: {
icon: {
type: 'string',
},
category: {
type: 'integer',
},
type: {
type: 'integer',
},
link: {
type: 'string',
},
tags: {
type: 'string',
},
description: {
type: 'string',
},
name: {
type: 'string',
},
},
},
},
},
},
},
},
};
================================================
FILE: packages/lisk-transactions/src/utils/validation/validate_transaction.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { ErrorObject, ValidateFunction } from 'ajv';
import {
MultiSignatureTransaction,
PartialTransaction,
} from '../../transaction_types';
import * as schemas from './schema';
import { validator } from './validator';
const TRANSACTION_TYPE_MULTI_SIGNATURE = 4;
const schemaMap: { readonly [key: number]: ValidateFunction } = {
0: validator.compile(schemas.transferTransaction),
1: validator.compile(schemas.signatureTransaction),
2: validator.compile(schemas.delegateTransaction),
3: validator.compile(schemas.voteTransaction),
4: validator.compile(schemas.multiTransaction),
5: validator.compile(schemas.dappTransaction),
};
const getTransactionSchemaValidator = (type: number): ValidateFunction => {
const schema = schemaMap[type];
if (!schema) {
throw new Error('Unsupported transaction type.');
}
return schema;
};
interface ValidationResult {
readonly errors?: ReadonlyArray;
readonly valid: boolean;
}
const validateMultiTransaction = (
tx: MultiSignatureTransaction,
): ValidationResult => {
if (tx.asset.multisignature.min > tx.asset.multisignature.keysgroup.length) {
return {
valid: false,
errors: [
{
dataPath: '.asset.multisignature.min',
keyword: 'multisignatures.keysgroup.min',
message:
'.asset.multisignature.min cannot be greater than .asset.multisignature.keysgroup.length',
params: {},
schemaPath: 'lisk/base-transaction',
},
] as ReadonlyArray,
};
}
return {
valid: true,
};
};
const isMultiSignatureTransaction = (
tx: PartialTransaction,
): tx is MultiSignatureTransaction =>
tx.type === TRANSACTION_TYPE_MULTI_SIGNATURE;
export const validateTransaction = (
tx: PartialTransaction,
): ValidationResult => {
if (tx.type === undefined || tx.type === null) {
throw new Error('Transaction type is required.');
}
const validateSchema = getTransactionSchemaValidator(tx.type);
const valid = validateSchema(tx) as boolean;
// Ajv produces merge error when error happens within $merge
const errors = validateSchema.errors
? validateSchema.errors.filter(
(e: { readonly keyword: string }) => e.keyword !== '$merge',
)
: undefined;
if (valid && isMultiSignatureTransaction(tx)) {
return validateMultiTransaction(tx);
}
return {
valid,
errors,
};
};
================================================
FILE: packages/lisk-transactions/src/utils/validation/validation.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
// tslint:disable-next-line no-reference
///
import * as cryptography from '@liskhq/lisk-cryptography';
import BigNum from 'browserify-bignum';
import {
MAX_ADDRESS_NUMBER,
MAX_TRANSACTION_AMOUNT,
MAX_TRANSACTION_ID,
MULTISIGNATURE_MAX_KEYSGROUP,
MULTISIGNATURE_MIN_KEYSGROUP,
} from '../../constants';
const MAX_PUBLIC_KEY_LENGTH = 32;
export const validatePublicKey = (publicKey: string) => {
const publicKeyBuffer = cryptography.hexToBuffer(publicKey);
if (publicKeyBuffer.length !== MAX_PUBLIC_KEY_LENGTH) {
throw new Error(
`Public key ${publicKey} length differs from the expected 32 bytes for a public key.`,
);
}
return true;
};
export const checkPublicKeysForDuplicates = (
publicKeys: ReadonlyArray,
) =>
publicKeys.every((element, index) => {
if (publicKeys.slice(index + 1).includes(element)) {
throw new Error(`Duplicated public key: ${publicKeys[index]}.`);
}
return true;
});
export const validatePublicKeys = (publicKeys: ReadonlyArray) =>
publicKeys.every(validatePublicKey) &&
checkPublicKeysForDuplicates(publicKeys);
export const validateKeysgroup = (keysgroup: ReadonlyArray) => {
if (
keysgroup.length < MULTISIGNATURE_MIN_KEYSGROUP ||
keysgroup.length > MULTISIGNATURE_MAX_KEYSGROUP
) {
throw new Error(
`Expected between ${MULTISIGNATURE_MIN_KEYSGROUP} and ${MULTISIGNATURE_MAX_KEYSGROUP} public keys in the keysgroup.`,
);
}
return validatePublicKeys(keysgroup);
};
const MIN_ADDRESS_LENGTH = 2;
const MAX_ADDRESS_LENGTH = 22;
const BASE_TEN = 10;
export const validateAddress = (address: string): boolean => {
if (
address.length < MIN_ADDRESS_LENGTH ||
address.length > MAX_ADDRESS_LENGTH
) {
throw new Error(
'Address length does not match requirements. Expected between 2 and 22 characters.',
);
}
if (address[address.length - 1] !== 'L') {
throw new Error(
'Address format does not match requirements. Expected "L" at the end.',
);
}
if (address.includes('.')) {
throw new Error(
'Address format does not match requirements. Address includes invalid character: `.`.',
);
}
const addressString = address.slice(0, -1);
const addressNumber = new BigNum(addressString);
if (addressNumber.cmp(new BigNum(MAX_ADDRESS_NUMBER)) > 0) {
throw new Error(
'Address format does not match requirements. Address out of maximum range.',
);
}
if (addressString !== addressNumber.toString(BASE_TEN)) {
throw new Error(
"Address string format does not match it's number representation.",
);
}
return true;
};
export const isGreaterThanZero = (amount: BigNum) => amount.cmp(0) > 0;
export const isGreaterThanMaxTransactionAmount = (amount: BigNum) =>
amount.cmp(MAX_TRANSACTION_AMOUNT) > 0;
export const isGreaterThanMaxTransactionId = (id: BigNum) =>
id.cmp(MAX_TRANSACTION_ID) > 0;
export const isNumberString = (str: string) => {
if (typeof str !== 'string') {
return false;
}
return /^[0-9]+$/g.test(str);
};
export const validateAmount = (data: string) =>
isNumberString(data) && !isGreaterThanZero(new BigNum(data));
export const validateTransferAmount = (data: string) =>
isNumberString(data) &&
isGreaterThanZero(new BigNum(data)) &&
!isGreaterThanMaxTransactionAmount(new BigNum(data));
export const validateFee = (data: string) =>
isNumberString(data) &&
isGreaterThanZero(new BigNum(data)) &&
!isGreaterThanMaxTransactionAmount(new BigNum(data));
export const isValidInteger = (num: unknown) =>
typeof num === 'number' ? Math.floor(num) === num : false;
================================================
FILE: packages/lisk-transactions/src/utils/validation/validator.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import Ajv from 'ajv';
import addKeywords from 'ajv-merge-patch';
import BigNum from 'browserify-bignum';
import * as schemas from './schema';
import {
isGreaterThanMaxTransactionId,
isNumberString,
validateAddress,
validateAmount,
validateFee,
validatePublicKey,
validateTransferAmount,
} from './validation';
export const validator = new Ajv({ allErrors: true });
addKeywords(validator);
validator.addFormat('signature', data => /^[a-f0-9]{128}$/i.test(data));
validator.addFormat(
'id',
data =>
isNumberString(data) && !isGreaterThanMaxTransactionId(new BigNum(data)),
);
validator.addFormat('address', data => {
try {
validateAddress(data);
return true;
} catch (error) {
return false;
}
});
validator.addFormat('amount', validateAmount);
validator.addFormat('transferAmount', validateTransferAmount);
validator.addFormat('fee', validateFee);
validator.addFormat('publicKey', data => {
try {
validatePublicKey(data);
return true;
} catch (error) {
return false;
}
});
validator.addFormat('signedPublicKey', data => {
try {
const action = data[0];
if (action !== '+' && action !== '-') {
return false;
}
const publicKey = data.slice(1);
validatePublicKey(publicKey);
return true;
} catch (error) {
return false;
}
});
validator.addFormat('additionPublicKey', data => {
const action = data[0];
if (action !== '+') {
return false;
}
try {
const publicKey = data.slice(1);
validatePublicKey(publicKey);
return true;
} catch (error) {
return false;
}
});
validator.addKeyword('uniqueSignedPublicKeys', {
type: 'array',
compile: () => (data: ReadonlyArray) =>
new Set(data.map((key: string) => key.slice(1))).size === data.length,
});
validator.addSchema(schemas.baseTransaction);
================================================
FILE: packages/lisk-transactions/test/0_transfer.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as cryptography from '@liskhq/lisk-cryptography';
import { transfer } from '../src/0_transfer';
import { TransferTransaction } from '../src/transaction_types';
import * as time from '../src/utils/time';
describe('#transfer transaction', () => {
const fixedPoint = 10 ** 8;
const testData = 'data';
const passphrase = 'secret';
const secondPassphrase = 'second secret';
const transactionType = 0;
const publicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const recipientId = '18160565574430594874L';
const recipientPublicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const recipientPublicKeyThatDoesNotMatchRecipientId =
'12345a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const amount = '1000';
const fee = (0.1 * fixedPoint).toString();
const timeWithOffset = 38350076;
let getTimeWithOffsetStub: sinon.SinonStub;
let transferTransaction: TransferTransaction;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
return Promise.resolve();
});
describe('with first passphrase', () => {
describe('without data', () => {
beforeEach(() => {
transferTransaction = transfer({
recipientId,
amount,
passphrase,
});
return Promise.resolve();
});
it('should create a transfer transaction', () => {
return expect(transferTransaction).to.be.ok;
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(undefined);
});
it('should use time.getTimeWithOffset with an offset of -10 seconds to calculate the timestamp', () => {
const offset = -10;
transfer({
recipientId,
amount,
passphrase,
timeOffset: offset,
});
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(offset);
});
it('should be an object', () => {
return expect(transferTransaction).to.be.an('object');
});
it('should have id string', () => {
return expect(transferTransaction)
.to.have.property('id')
.and.be.a('string');
});
it('should have type number equal to 0', () => {
return expect(transferTransaction)
.to.have.property('type')
.and.be.a('number')
.and.equal(transactionType);
});
it('should have amount string equal to provided amount', () => {
return expect(transferTransaction)
.to.have.property('amount')
.and.be.a('string')
.and.equal(amount);
});
it('should have fee string equal to transfer fee', () => {
return expect(transferTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(fee);
});
it('should have recipientId string equal to provided recipient id', () => {
return expect(transferTransaction)
.to.have.property('recipientId')
.and.be.a('string')
.and.equal(recipientId);
});
it('should have senderPublicKey hex string equal to sender public key', () => {
return expect(transferTransaction)
.to.have.property('senderPublicKey')
.and.be.hexString.and.equal(publicKey);
});
it('should have timestamp number equal to result of time.getTimeWithOffset', () => {
return expect(transferTransaction)
.to.have.property('timestamp')
.and.be.a('number')
.and.equal(timeWithOffset);
});
it('should have signature hex string', () => {
return expect(transferTransaction).to.have.property('signature').and.be
.hexString;
});
it('should have an empty asset object', () => {
return expect(transferTransaction)
.to.have.property('asset')
.and.be.an('object').and.be.empty;
});
it('should not have the second signature property', () => {
return expect(transferTransaction).not.to.have.property(
'signSignature',
);
});
});
describe('with data', () => {
beforeEach(() => {
transferTransaction = transfer({
recipientId,
amount,
passphrase,
data: testData,
});
return Promise.resolve();
});
it('should handle invalid (non-utf8 string) data', () => {
return expect(
transfer.bind(null, {
recipientId,
amount,
passphrase,
data: Buffer.from('hello'),
}),
).to.throw(
'Invalid encoding in transaction data. Data must be utf-8 encoded string.',
);
});
it('should have fee string equal to transfer fee', () => {
return expect(transferTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(fee);
});
describe('data asset', () => {
it('should be a string equal to provided data', () => {
return expect(transferTransaction.asset)
.to.have.property('data')
.and.be.a('string')
.and.equal(testData);
});
});
});
});
describe('with first and second passphrase', () => {
beforeEach(() => {
transferTransaction = transfer({
recipientId,
amount,
passphrase,
secondPassphrase,
});
return Promise.resolve();
});
it('should create a transfer transaction with data property', () => {
transferTransaction = transfer({
recipientId,
amount,
passphrase,
secondPassphrase,
data: testData,
});
return expect(transferTransaction.asset).to.have.property('data');
});
it('should have the second signature property as hex string', () => {
return expect(transferTransaction).to.have.property('signSignature').and
.be.hexString;
});
});
describe('unsigned transfer transaction', () => {
describe('when the transfer transaction is created without a passphrase', () => {
beforeEach(() => {
transferTransaction = transfer({
recipientId,
amount,
});
return Promise.resolve();
});
it('should throw error when amount is 0', () => {
return expect(
transfer.bind(null, {
amount: '0',
}),
).to.throw('Amount must be a valid number in string format.');
});
it('should throw error when amount is greater than max transaction amount', () => {
return expect(
transfer.bind(null, {
amount: '18446744073709551616',
}),
).to.throw('Amount must be a valid number in string format.');
});
it('should throw error when recipientId & non-matching recipientPublicKey provided', () => {
return expect(
transfer.bind(null, {
amount,
recipientId,
recipientPublicKey: recipientPublicKeyThatDoesNotMatchRecipientId,
}),
).to.throw('recipientId does not match recipientPublicKey.');
});
it('should non throw error when recipientId & matching recipientPublicKey provided', () => {
return expect(
transfer.bind(null, {
amount,
recipientId,
recipientPublicKey,
}),
).to.not.throw();
});
it('should throw error when both recipientId and recipientPublicKey were not provided', () => {
return expect(
transfer.bind(null, {
amount,
passphrase,
data: Buffer.from('hello'),
}),
).to.throw(
'Either recipientId or recipientPublicKey must be provided.',
);
});
it('should set recipientId when recipientId was not provided but recipientPublicKey was provided', () => {
const tx = transfer({
amount,
passphrase,
recipientPublicKey: publicKey,
});
return expect(tx)
.to.have.property('recipientId')
.and.be.a('string')
.to.equal(cryptography.getAddressFromPublicKey(publicKey));
});
it('should handle too much data', () => {
return expect(
transfer.bind(null, {
recipientId,
amount,
data: new Array(65).fill('0').join(''),
}),
).to.throw('Transaction data field cannot exceed 64 bytes.');
});
it('should have the type', () => {
return expect(transferTransaction)
.to.have.property('type')
.equal(transactionType);
});
it('should have the amount', () => {
return expect(transferTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the fee', () => {
return expect(transferTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the recipient', () => {
return expect(transferTransaction)
.to.have.property('recipientId')
.equal(recipientId);
});
it('should have the sender public key', () => {
return expect(transferTransaction)
.to.have.property('senderPublicKey')
.equal(undefined);
});
it('should have the timestamp', () => {
return expect(transferTransaction).to.have.property('timestamp');
});
it('should have the asset', () => {
return expect(transferTransaction).to.have.property('asset');
});
it('should not have the signature', () => {
return expect(transferTransaction).not.to.have.property('signature');
});
it('should not have the id', () => {
return expect(transferTransaction).not.to.have.property('id');
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/1_register_second_passphrase.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { registerSecondPassphrase } from '../src/1_register_second_passphrase';
import {
SecondSignatureAsset,
SecondSignatureTransaction,
} from '../src/transaction_types';
import * as time from '../src/utils/time';
describe('#registerSecondPassphrase transaction', () => {
const fixedPoint = 10 ** 8;
const passphrase = 'secret';
const secondPassphrase = 'second secret';
const transactionType = 1;
const publicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const secondPublicKey =
'0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
const emptyStringPublicKey =
'be907b4bac84fee5ce8811db2defc9bf0b2a2a2bbc3d54d8a2257ecd70441962';
const secondPassphraseFee = (5 * fixedPoint).toString();
const timeWithOffset = 38350076;
const fee = (5 * fixedPoint).toString();
const amount = '0';
let getTimeWithOffsetStub: sinon.SinonStub;
let registerSecondPassphraseTransaction: SecondSignatureTransaction;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
registerSecondPassphraseTransaction = registerSecondPassphrase({
passphrase,
secondPassphrase,
});
return Promise.resolve();
});
it('should create a register second passphrase transaction', () => {
return expect(registerSecondPassphraseTransaction).to.be.ok;
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(undefined);
});
it('should use time.getTimeWithOffset with an offset of -10 seconds to calculate the timestamp', () => {
const offset = -10;
registerSecondPassphrase({
passphrase,
secondPassphrase,
timeOffset: offset,
});
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(offset);
});
describe('returned register second passphrase transaction', () => {
it('should be an object', () => {
return expect(registerSecondPassphraseTransaction).to.be.an('object');
});
it('should have an id string', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('id')
.and.be.a('string');
});
it('should have type number equal to 1', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('type')
.and.be.a('number')
.and.equal(transactionType);
});
it('should have amount string equal to 0', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('amount')
.and.be.a('string')
.and.equal(amount);
});
it('should have fee string equal to second passphrase fee', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(secondPassphraseFee);
});
it('should have recipientId equal to empty string', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('recipientId')
.and.equal('');
});
it('should have senderPublicKey hex string equal to sender public key', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('senderPublicKey')
.and.be.hexString.and.equal(publicKey);
});
it('should have timestamp number equal to result of time.getTimeWithOffset', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('timestamp')
.and.be.a('number')
.and.equal(timeWithOffset);
});
it('should have signature hex string', () => {
return expect(registerSecondPassphraseTransaction).to.have.property(
'signature',
).and.be.hexString;
});
it('should have asset object', () => {
return expect(registerSecondPassphraseTransaction).to.have.property(
'asset',
).and.not.be.empty;
});
it('should not have a signSignature property', () => {
return expect(registerSecondPassphraseTransaction).not.to.have.property(
'signSignature',
);
});
describe('signature asset', () => {
it('should be an object', () => {
return expect(registerSecondPassphraseTransaction.asset)
.to.have.property('signature')
.and.be.an('object').and.not.be.empty;
});
it('should have a 32-byte publicKey hex string', () => {
expect(registerSecondPassphraseTransaction.asset)
.to.have.property('signature')
.with.property('publicKey').and.be.hexString;
const {
signature,
} = registerSecondPassphraseTransaction.asset as SecondSignatureAsset;
return expect(Buffer.from(signature.publicKey, 'hex')).to.have.length(
32,
);
});
it('should have a publicKey equal to the public key for the provided second passphrase', () => {
return expect(registerSecondPassphraseTransaction.asset)
.to.have.property('signature')
.with.property('publicKey')
.and.equal(secondPublicKey);
});
it('should have the correct publicKey if the provided second passphrase is an empty string', () => {
registerSecondPassphraseTransaction = registerSecondPassphrase({
passphrase,
secondPassphrase: '',
});
const {
signature,
} = registerSecondPassphraseTransaction.asset as SecondSignatureAsset;
return expect(signature.publicKey).to.be.equal(emptyStringPublicKey);
});
});
});
describe('unsigned register second passphrase transaction', () => {
describe('when the register second passphrase transaction is created without a passphrase', () => {
beforeEach(() => {
registerSecondPassphraseTransaction = registerSecondPassphrase({
secondPassphrase,
});
return Promise.resolve();
});
it('should throw error when secondPassphrase was not provided', () => {
return expect(registerSecondPassphrase.bind(null, {})).to.throw(
'Please provide a secondPassphrase. Expected string.',
);
});
it('should not throw error when secondPassphrase is empty string', () => {
return expect(
registerSecondPassphrase.bind(null, { secondPassphrase: '' }),
).to.not.throw();
});
it('should have the type', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('type')
.equal(transactionType);
});
it('should have the amount', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the fee', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the recipient', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('recipientId')
.equal('');
});
it('should have the sender public key', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('senderPublicKey')
.equal(undefined);
});
it('should have the timestamp', () => {
return expect(registerSecondPassphraseTransaction).to.have.property(
'timestamp',
);
});
it('should have the asset with the signature with the public key', () => {
return expect(registerSecondPassphraseTransaction)
.to.have.property('asset')
.with.property('signature')
.with.property('publicKey')
.of.a('string');
});
it('should not have the signature', () => {
return expect(registerSecondPassphraseTransaction).not.to.have.property(
'signature',
);
});
it('should not have the id', () => {
return expect(registerSecondPassphraseTransaction).not.to.have.property(
'id',
);
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/2_register_delegate.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { registerDelegate } from '../src/2_register_delegate';
import { DelegateAsset, DelegateTransaction } from '../src/transaction_types';
// Require is used for stubbing
const time = require('../src/utils/time');
describe('#registerDelegate transaction', () => {
const fixedPoint = 10 ** 8;
const passphrase = 'secret';
const secondPassphrase = 'second secret';
const transactionType = 2;
const publicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const username = 'test_delegate_1@\\';
const fee = (25 * fixedPoint).toString();
const timeWithOffset = 38350076;
const amount = '0';
let getTimeWithOffsetStub: sinon.SinonStub;
let registerDelegateTransaction: DelegateTransaction;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
return Promise.resolve();
});
describe('with first passphrase', () => {
beforeEach(() => {
registerDelegateTransaction = registerDelegate({
passphrase,
username,
});
return Promise.resolve();
});
it('should create a register delegate transaction', () => {
return expect(registerDelegateTransaction).to.be.ok;
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(undefined);
});
it('should use time.getTimeWithOffset with an offset of -10 seconds to calculate the timestamp', () => {
const offset = -10;
registerDelegate({ passphrase, username, timeOffset: offset });
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(offset);
});
it('should be an object', () => {
return expect(registerDelegateTransaction).to.be.an('object');
});
it('should have an id string', () => {
return expect(registerDelegateTransaction)
.to.have.property('id')
.and.be.a('string');
});
it('should have type number equal to 2', () => {
return expect(registerDelegateTransaction)
.to.have.property('type')
.and.be.a('number')
.and.equal(transactionType);
});
it('should have amount string equal to 0', () => {
return expect(registerDelegateTransaction)
.to.have.property('amount')
.and.be.a('string')
.and.equal(amount);
});
it('should have fee string equal to 25 LSK', () => {
return expect(registerDelegateTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(fee);
});
it('should have recipientId equal to empty string', () => {
return expect(registerDelegateTransaction)
.to.have.property('recipientId')
.and.equal('');
});
it('should have senderPublicKey hex string equal to sender public key', () => {
return expect(registerDelegateTransaction)
.to.have.property('senderPublicKey')
.and.be.hexString.and.equal(publicKey);
});
it('should have timestamp number equal to result of time.getTimeWithOffset', () => {
return expect(registerDelegateTransaction)
.to.have.property('timestamp')
.and.be.a('number')
.and.equal(timeWithOffset);
});
it('should have signature hex string', () => {
return expect(registerDelegateTransaction).to.have.property('signature')
.and.be.hexString;
});
it('should not have the second signature property', () => {
return expect(registerDelegateTransaction).not.to.have.property(
'signSignature',
);
});
it('should have asset', () => {
return expect(registerDelegateTransaction).to.have.property('asset').and
.not.be.empty;
});
describe('delegate asset', () => {
it('should be an object', () => {
return expect(registerDelegateTransaction.asset)
.to.have.property('delegate')
.and.be.an('object');
});
it('should have the provided username as a string', () => {
const { delegate } = registerDelegateTransaction.asset as DelegateAsset;
return expect(delegate)
.to.have.property('username')
.and.be.a('string')
.and.equal(username);
});
});
});
describe('with first and second passphrase', () => {
beforeEach(() => {
registerDelegateTransaction = registerDelegate({
passphrase,
username,
secondPassphrase,
});
return Promise.resolve();
});
it('should have the second signature property as hex string', () => {
return expect(registerDelegateTransaction).to.have.property(
'signSignature',
).and.be.hexString;
});
});
describe('unsigned register delegate transaction', () => {
describe('when the register delegate transaction is created without a passphrase', () => {
beforeEach(() => {
registerDelegateTransaction = registerDelegate({
username,
});
return Promise.resolve();
});
it('should throw error when username was not provided', () => {
return expect(registerDelegate.bind(null, {})).to.throw(
'Please provide a username. Expected string.',
);
});
it('should throw error when username is empty string', () => {
return expect(registerDelegate.bind(null, { username: '' })).to.throw(
'Please provide a username. Expected string.',
);
});
it('should throw error when invalid username was provided', () => {
return expect(
registerDelegate.bind(null, { username: '12345678901234567890a' }),
).to.throw(
'Username length does not match requirements. Expected to be no more than 20 characters.',
);
});
it('should have the type', () => {
return expect(registerDelegateTransaction)
.to.have.property('type')
.equal(transactionType);
});
it('should have the amount', () => {
return expect(registerDelegateTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the fee', () => {
return expect(registerDelegateTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the recipient id', () => {
return expect(registerDelegateTransaction)
.to.have.property('recipientId')
.equal('');
});
it('should have the sender public key', () => {
return expect(registerDelegateTransaction)
.to.have.property('senderPublicKey')
.equal(undefined);
});
it('should have the timestamp', () => {
return expect(registerDelegateTransaction).to.have.property(
'timestamp',
);
});
it('should have the asset with the delegate', () => {
return expect(registerDelegateTransaction)
.to.have.property('asset')
.with.property('delegate')
.with.property('username');
});
it('should not have the signature', () => {
return expect(registerDelegateTransaction).not.to.have.property(
'signature',
);
});
it('should not have the id', () => {
return expect(registerDelegateTransaction).not.to.have.property('id');
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/3_cast_votes.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { castVotes } from '../src/3_cast_votes';
import { VoteAsset, VoteTransaction } from '../src/transaction_types';
// Require is used for stubbing
const time = require('../src/utils/time');
describe('#castVotes transaction', () => {
const fixedPoint = 10 ** 8;
const passphrase = 'secret';
const secondPassphrase = 'second secret';
const transactionType = 3;
const firstPublicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const secondPublicKey =
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa';
const thirdPublicKey =
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca';
const fourthPublicKey =
'd019a4b6fa37e8ebeb64766c7b239d962fb3b3f265b8d3083206097b912cd914';
const tooShortPublicKey =
'd019a4b6fa37e8ebeb64766c7b239d962fb3b3f265b8d3083206097b912cd9';
const plusPrependedPublicKey =
'+5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const votePublicKeys = [firstPublicKey, secondPublicKey];
const unvotePublicKeys = [thirdPublicKey, fourthPublicKey];
const address = '18160565574430594874L';
const timeWithOffset = 38350076;
const amount = '0';
const fee = (1 * fixedPoint).toString();
let getTimeWithOffsetStub: sinon.SinonStub;
let castVotesTransaction: VoteTransaction;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
return Promise.resolve();
});
describe('when the transaction is created with one passphrase and the votes', () => {
beforeEach(() => {
castVotesTransaction = castVotes({
passphrase,
votes: votePublicKeys,
});
return Promise.resolve();
});
it('should create a cast votes transaction', () => {
return expect(castVotesTransaction).to.be.ok;
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(undefined);
});
it('should use time.getTimeWithOffset with an offset of -10 seconds to calculate the timestamp', () => {
const offset = -10;
castVotes({ passphrase, votes: votePublicKeys, timeOffset: offset });
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(offset);
});
describe('the returned cast votes transaction', () => {
it('should be an object', () => {
return expect(castVotesTransaction).to.be.an('object');
});
it('should have id string', () => {
return expect(castVotesTransaction)
.to.have.property('id')
.and.be.a('string');
});
it('should have type number equal to 3', () => {
return expect(castVotesTransaction)
.to.have.property('type')
.and.be.a('number')
.and.equal(transactionType);
});
it('should have amount string equal to 0', () => {
return expect(castVotesTransaction)
.to.have.property('amount')
.and.be.a('string')
.and.equal(amount);
});
it('should have fee string equal to 100000000', () => {
return expect(castVotesTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(fee);
});
it('should have recipientId string equal to address', () => {
return expect(castVotesTransaction)
.to.have.property('recipientId')
.and.be.a('string')
.and.equal(address);
});
it('should have senderPublicKey hex string equal to sender public key', () => {
return expect(castVotesTransaction)
.to.have.property('senderPublicKey')
.and.be.hexString.and.equal(firstPublicKey);
});
it('should have timestamp number equal to result of time.getTimeWithOffset', () => {
return expect(castVotesTransaction)
.to.have.property('timestamp')
.and.be.a('number')
.and.equal(timeWithOffset);
});
it('should have signature hex string', () => {
return expect(castVotesTransaction).to.have.property('signature').and.be
.hexString;
});
it('should not have the second signature property', () => {
return expect(castVotesTransaction).not.to.have.property(
'signSignature',
);
});
it('should have asset', () => {
return expect(castVotesTransaction).to.have.property('asset').and.not.be
.empty;
});
describe('votes asset', () => {
it('should be array', () => {
return expect(castVotesTransaction.asset)
.to.have.property('votes')
.and.be.an('array');
});
it('should contain two elements', () => {
const { votes } = castVotesTransaction.asset as VoteAsset;
return expect(votes).to.have.length(2);
});
it('should have a vote for the delegate public key', () => {
const { votes } = castVotesTransaction.asset as VoteAsset;
const expectedArray = [`+${firstPublicKey}`, `+${secondPublicKey}`];
return expect(votes).to.be.eql(expectedArray);
});
});
});
});
describe('with first and second passphrase', () => {
beforeEach(() => {
castVotesTransaction = castVotes({
passphrase,
votes: [firstPublicKey],
secondPassphrase,
});
return Promise.resolve();
});
it('should have the second signature property as hex string', () => {
return expect(castVotesTransaction).to.have.property('signSignature').and
.be.hexString;
});
});
describe('when the cast vote transaction is created with the votes and unvotes', () => {
beforeEach(() => {
castVotesTransaction = castVotes({
passphrase,
votes: votePublicKeys,
unvotes: unvotePublicKeys,
});
return Promise.resolve();
});
it('the transaction should have the votes as an array', () => {
return expect(castVotesTransaction.asset)
.to.have.property('votes')
.and.be.an('array');
});
it('the transaction should have the votes and the unvotes', () => {
const expectedArray = [
`+${firstPublicKey}`,
`+${secondPublicKey}`,
`-${thirdPublicKey}`,
`-${fourthPublicKey}`,
];
const { votes } = castVotesTransaction.asset as VoteAsset;
return expect(votes).to.be.eql(expectedArray);
});
});
describe('when the cast vote transaction is created with the invalid votes and invalid unvotes', () => {
it('should throw error when null was provided for votes', () => {
return expect(
castVotes.bind(null, {
passphrase,
votes: null,
}),
).to.throw(
'Please provide a valid votes value. Expected an array if present.',
);
});
it('should throw error when string was provided for votes', () => {
return expect(
castVotes.bind(null, {
passphrase,
votes: `+${firstPublicKey}`,
}),
).to.throw(
'Please provide a valid votes value. Expected an array if present.',
);
});
it('should throw error when null was provided for unvotes', () => {
return expect(
castVotes.bind(null, {
passphrase,
unvotes: null,
}),
).to.throw(
'Please provide a valid unvotes value. Expected an array if present.',
);
});
it('should throw error when string was provided for unvotes', () => {
return expect(
castVotes.bind(null, {
passphrase,
unvotes: `-${firstPublicKey}`,
}),
).to.throw(
'Please provide a valid unvotes value. Expected an array if present.',
);
});
});
describe('when the cast vote transaction is created with the unvotes', () => {
beforeEach(() => {
castVotesTransaction = castVotes({
passphrase,
unvotes: unvotePublicKeys,
});
return Promise.resolve();
});
it('the transaction should have the votes array', () => {
return expect(castVotesTransaction.asset)
.to.have.property('votes')
.and.be.an('array');
});
it('the transaction asset should have the unvotes', () => {
const expectedArray = [`-${thirdPublicKey}`, `-${fourthPublicKey}`];
const { votes } = castVotesTransaction.asset as VoteAsset;
return expect(votes).to.be.eql(expectedArray);
});
});
describe('when the cast vote transaction is created with one too short public key', () => {
it('should throw an error', () => {
return expect(
castVotes.bind(null, {
passphrase,
unvotes: unvotePublicKeys,
votes: [tooShortPublicKey],
}),
).to.throw(
'Public key d019a4b6fa37e8ebeb64766c7b239d962fb3b3f265b8d3083206097b912cd9 length differs from the expected 32 bytes for a public key.',
);
});
});
describe('when the cast vote transaction is created with one plus prepended public key', () => {
it('should throw an error', () => {
return expect(
castVotes.bind(null, {
passphrase,
unvotes: unvotePublicKeys,
votes: [plusPrependedPublicKey],
}),
).to.throw('Argument must be a valid hex string.');
});
});
describe('when the cast vote transaction is created with duplicated public keys', () => {
describe('Given votes and unvotes with duplication', () => {
it('should throw a duplication error', () => {
const votes = [firstPublicKey, secondPublicKey];
const unvotes = [firstPublicKey, thirdPublicKey];
return expect(
castVotes.bind(null, {
passphrase,
unvotes,
votes,
}),
).to.throw(
'Duplicated public key: 5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09.',
);
});
});
describe('Given votes with duplication', () => {
it('should throw a duplication error for votes', () => {
const votes = [firstPublicKey, secondPublicKey, firstPublicKey];
return expect(
castVotes.bind(null, {
passphrase,
votes,
}),
).to.throw(
'Duplicated public key: 5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09.',
);
});
});
describe('Given unvotes with duplication', () => {
it('should throw a duplication error for unvotes', () => {
const unvotes = [firstPublicKey, secondPublicKey, firstPublicKey];
return expect(
castVotes.bind(null, {
passphrase,
unvotes,
}),
).to.throw(
'Duplicated public key: 5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09.',
);
});
});
});
describe('unsigned cast votes transaction', () => {
describe('when the cast votes transaction is created without a passphrase', () => {
beforeEach(() => {
castVotesTransaction = castVotes({
votes: votePublicKeys,
unvotes: unvotePublicKeys,
});
return Promise.resolve();
});
it('should have the type', () => {
return expect(castVotesTransaction)
.to.have.property('type')
.equal(transactionType);
});
it('should have the amount', () => {
return expect(castVotesTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the fee', () => {
return expect(castVotesTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the recipient id', () => {
return expect(castVotesTransaction)
.to.have.property('recipientId')
.equal('');
});
it('should have the sender public key', () => {
return expect(castVotesTransaction)
.to.have.property('senderPublicKey')
.equal(undefined);
});
it('should have the timestamp', () => {
return expect(castVotesTransaction).to.have.property('timestamp');
});
it('should have the asset with the votes', () => {
return expect(castVotesTransaction)
.to.have.property('asset')
.with.property('votes');
});
it('should not have the signature', () => {
return expect(castVotesTransaction).not.to.have.property('signature');
});
it('should not have the id', () => {
return expect(castVotesTransaction).not.to.have.property('id');
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/4_register_multisignature_account.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as cryptography from '@liskhq/lisk-cryptography';
import { registerMultisignature } from '../src/4_register_multisignature_account';
import {
MultiSignatureAsset,
MultiSignatureTransaction,
} from '../src/transaction_types';
// Require is used for stubbing
const time = require('../src/utils/time');
describe('#registerMultisignature transaction', () => {
const fixedPoint = 10 ** 8;
const passphrase = 'secret';
const secondPassphrase = 'second secret';
const transactionType = 4;
const keys = {
publicKey:
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
privateKey:
'2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
};
const timeWithOffset = 38350076;
const fee = (15 * fixedPoint).toString();
const amount = '0';
const lifetime = 5;
const minimum = 2;
let tooShortPublicKeyKeysgroup: Array;
let plusPrependedPublicKeyKeysgroup: Array;
let keysgroup: Array;
let getTimeWithOffsetStub: sinon.SinonStub;
let registerMultisignatureTransaction: MultiSignatureTransaction;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
keysgroup = [
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
];
plusPrependedPublicKeyKeysgroup = [
'+5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
tooShortPublicKeyKeysgroup = [
'd019a4b6fa37e8ebeb64766c7b239d962fb3b3f265b8d3083206097b912cd9',
];
return Promise.resolve();
});
describe('with first passphrase', () => {
beforeEach(() => {
registerMultisignatureTransaction = registerMultisignature({
passphrase,
keysgroup,
lifetime,
minimum,
});
return Promise.resolve();
});
it('should create a register multisignature transaction', () => {
return expect(registerMultisignatureTransaction).to.be.ok;
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(undefined);
});
it('should use time.getTimeWithOffset with an offset of -10 seconds to calculate the timestamp', () => {
const offset = -10;
registerMultisignature({
passphrase,
keysgroup,
lifetime,
minimum,
timeOffset: offset,
});
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(offset);
});
describe('returned register multisignature transaction', () => {
it('should be an object', () => {
return expect(registerMultisignatureTransaction).to.be.an('object');
});
it('should have id string', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('id')
.and.be.a('string');
});
it('should have type number equal to 4', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('type')
.and.be.a('number')
.and.equal(transactionType);
});
it('should have amount string equal to 0', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('amount')
.and.be.a('string')
.and.equal(amount);
});
it('should have fee string equal to 15 LSK', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(fee);
});
it('should have recipientId string equal to empty string', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('recipientId')
.and.equal('');
});
it('should have senderPublicKey hex string equal to sender public key', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('senderPublicKey')
.and.be.hexString.and.equal(keys.publicKey);
});
it('should have timestamp number equal to result of time.getTimeWithOffset', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('timestamp')
.and.be.a('number')
.and.equal(timeWithOffset);
});
it('should have signature hex string', () => {
return expect(registerMultisignatureTransaction).to.have.property(
'signature',
).and.be.hexString;
});
it('should have asset', () => {
return expect(registerMultisignatureTransaction).to.have.property(
'asset',
).and.not.be.empty;
});
it('should not have a second signature', () => {
return expect(registerMultisignatureTransaction).not.to.have.property(
'signSignature',
);
});
describe('multisignature asset', () => {
it('should be object', () => {
return expect(registerMultisignatureTransaction.asset)
.to.have.property('multisignature')
.and.be.an('object');
});
it('should have a min number equal to provided minimum', () => {
const {
multisignature,
} = registerMultisignatureTransaction.asset as MultiSignatureAsset;
return expect(multisignature)
.to.have.property('min')
.and.be.a('number')
.and.be.equal(minimum);
});
it('should have a lifetime number equal to provided lifetime', () => {
const {
multisignature,
} = registerMultisignatureTransaction.asset as MultiSignatureAsset;
return expect(multisignature)
.to.have.property('lifetime')
.and.be.a('number')
.and.be.equal(lifetime);
});
it('should have a keysgroup array with plus prepended', () => {
const expectedArray = [
'+5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
'+922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
];
const {
multisignature,
} = registerMultisignatureTransaction.asset as MultiSignatureAsset;
return expect(multisignature)
.to.have.property('keysgroup')
.and.be.eql(expectedArray);
});
});
});
});
describe('with first and second passphrase', () => {
beforeEach(() => {
registerMultisignatureTransaction = registerMultisignature({
passphrase,
secondPassphrase,
keysgroup,
lifetime,
minimum,
});
return Promise.resolve();
});
it('should have the second signature property as hex string', () => {
return expect(registerMultisignatureTransaction).to.have.property(
'signSignature',
).and.be.hexString;
});
});
describe('when the register multisignature account transaction is created with one too short public key', () => {
it('should throw an error', () => {
return expect(
registerMultisignature.bind(null, {
passphrase,
secondPassphrase,
keysgroup: tooShortPublicKeyKeysgroup,
lifetime,
minimum: 1,
}),
).to.throw(
'Public key d019a4b6fa37e8ebeb64766c7b239d962fb3b3f265b8d3083206097b912cd9 length differs from the expected 32 bytes for a public key.',
);
});
});
describe('when the register multisignature account transaction is created with one plus prepended public key', () => {
it('should throw an error', () => {
return expect(
registerMultisignature.bind(null, {
passphrase,
secondPassphrase,
keysgroup: plusPrependedPublicKeyKeysgroup,
lifetime,
minimum: 1,
}),
).to.throw('Argument must be a valid hex string.');
});
});
describe('when the register multisignature account transaction is created with one empty keysgroup', () => {
it('should throw an error', () => {
return expect(
registerMultisignature.bind(null, {
passphrase,
secondPassphrase,
keysgroup: [],
lifetime,
minimum,
}),
).to.throw(
'Minimum number of signatures is larger than the number of keys in the keysgroup.',
);
});
});
describe('when the register multisignature account transaction is created with 17 public keys in keysgroup', () => {
beforeEach(() => {
keysgroup = Array(17)
.fill(0)
.map(
(_: number, index: number) =>
cryptography.getPrivateAndPublicKeyFromPassphrase(index.toString())
.publicKey,
);
return Promise.resolve();
});
it('should throw an error', () => {
return expect(
registerMultisignature.bind(null, {
passphrase,
secondPassphrase,
keysgroup,
lifetime,
minimum,
}),
).to.throw('Expected between 1 and 15 public keys in the keysgroup.');
});
});
describe('when the register multisignature account transaction is created with duplicated public keys', () => {
beforeEach(() => {
keysgroup = [keys.publicKey, keys.publicKey];
return Promise.resolve();
});
it('should throw an error', () => {
return expect(
registerMultisignature.bind(null, {
passphrase,
secondPassphrase,
keysgroup,
lifetime,
minimum,
}),
).to.throw(
'Duplicated public key: 5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09.',
);
});
});
describe('unsigned register multisignature account transaction', () => {
describe('when the register multisignature transaction is created without a passphrase', () => {
beforeEach(() => {
registerMultisignatureTransaction = registerMultisignature({
keysgroup,
lifetime,
minimum,
});
return Promise.resolve();
});
describe('validation errors', () => {
describe('when lifetime', () => {
const lifetimeErrorMessage =
'Please provide a valid lifetime value. Expected integer between 1 and 72.';
it('was not provided', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
}),
).to.throw(lifetimeErrorMessage);
});
it('is float', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime: 23.45,
}),
).to.throw(lifetimeErrorMessage);
});
it('is not number type', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime: '123',
}),
).to.throw(lifetimeErrorMessage);
});
it('was more than expected', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime: 73,
}),
).to.throw(lifetimeErrorMessage);
});
it('was less than expected', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime: -1,
}),
).to.throw(lifetimeErrorMessage);
});
});
});
describe('when minimum', () => {
const minimumErrorMessage =
'Please provide a valid minimum value. Expected integer between 1 and 15.';
it('was not provided', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime,
}),
).to.throw(minimumErrorMessage);
});
it('is float', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime,
minimum: 1.45,
}),
).to.throw(minimumErrorMessage);
});
it('is not number type', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime,
minimum: '12',
}),
).to.throw(minimumErrorMessage);
});
it('was more than expected', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime,
minimum: 16,
}),
).to.throw(minimumErrorMessage);
});
it('was less than expected', () => {
return expect(
registerMultisignature.bind(null, {
keysgroup,
lifetime,
minimum: -1,
}),
).to.throw(minimumErrorMessage);
});
});
it('should have the type', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('type')
.equal(transactionType);
});
it('should have the amount', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the fee', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the recipient id', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('recipientId')
.equal('');
});
it('should have the sender public key', () => {
return expect(registerMultisignatureTransaction)
.to.have.property('senderPublicKey')
.equal(undefined);
});
it('should have the timestamp', () => {
return expect(registerMultisignatureTransaction).to.have.property(
'timestamp',
);
});
it('should have the asset with the multisignature with the min, lifetime and keysgroup', () => {
return expect(registerMultisignatureTransaction)
.to.have.nested.property('asset.multisignature')
.with.all.keys('min', 'lifetime', 'keysgroup');
});
it('should not have the signature', () => {
return expect(registerMultisignatureTransaction).not.to.have.property(
'signature',
);
});
it('should not have the id', () => {
return expect(registerMultisignatureTransaction).not.to.have.property(
'id',
);
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/5_create_dapp.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { createDapp, DappOptions } from '../src/5_create_dapp';
import { DappAsset, DappTransaction } from '../src/transaction_types';
// Require is used for stubbing
const time = require('../src/utils/time');
describe('#createDapp transaction', () => {
const fixedPoint = 10 ** 8;
const transactionType = 5;
const amount = '0';
const passphrase = 'secret';
const secondPassphrase = 'second secret';
const publicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultOptions = {
category: 0,
name: 'Lisk Guestbook',
description: 'The official Lisk guestbook',
tags: 'guestbook message sidechain',
type: 0,
link: 'https://github.com/MaxKK/guestbookDapp/archive/master.zip',
icon:
'https://raw.githubusercontent.com/MaxKK/guestbookDapp/master/icon.png',
};
const fee = (25 * fixedPoint).toString();
const timeWithOffset = 38350076;
const noOptionsError = 'Options must be an object.';
const categoryIntegerError = 'Dapp category must be an integer.';
const nameStringError = 'Dapp name must be a string.';
const typeIntegerError = 'Dapp type must be an integer.';
const linkStringError = 'Dapp link must be a string.';
const descriptionStringError =
'Dapp description must be a string if provided.';
const tagsStringError = 'Dapp tags must be a string if provided.';
const iconStringError = 'Dapp icon must be a string if provided.';
let getTimeWithOffsetStub: sinon.SinonStub;
let options: DappOptions;
let createDappTransaction: DappTransaction;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
options = {
...defaultOptions,
};
return Promise.resolve();
});
describe('with first passphrase', () => {
beforeEach(() => {
createDappTransaction = createDapp({ passphrase, options });
return Promise.resolve();
});
it('should create a create dapp transaction', () => {
return expect(createDappTransaction).to.be.ok;
});
it('should throw an error if no options are provided', () => {
return expect(createDapp.bind(null, { passphrase })).to.throw(
noOptionsError,
);
});
it('should throw an error if no category is provided', () => {
const { category, ...invalidOptions } = options;
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(categoryIntegerError);
});
it('should throw an error if provided category is not an integer', () => {
const invalidOptions = {
...options,
category: 'not an integer',
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(categoryIntegerError);
});
it('should throw an error if no name is provided', () => {
const { name, ...invalidOptions } = options;
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(nameStringError);
});
it('should throw an error if provided name is not a string', () => {
const invalidOptions = {
...options,
name: 123,
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(nameStringError);
});
it('should throw an error if no type is provided', () => {
const { type, ...invalidOptions } = options;
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(typeIntegerError);
});
it('should throw an error if provided type is not an integer', () => {
const invalidOptions = {
...options,
type: 'not an integer',
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(typeIntegerError);
});
it('should throw an error if no link is provided', () => {
const { link, ...invalidOptions } = options;
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(linkStringError);
});
it('should throw an error if provided link is not a string', () => {
const invalidOptions = {
...options,
link: 123,
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(linkStringError);
});
it('should throw an error if provided description is not a string', () => {
const invalidOptions = {
...options,
description: 123,
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(descriptionStringError);
});
it('should throw an error if provided tags is not a string', () => {
const invalidOptions = {
...options,
tags: 123,
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(tagsStringError);
});
it('should throw an error if provided icon is not a string', () => {
const invalidOptions = {
...options,
icon: 123,
};
return expect(
createDapp.bind(null, { passphrase, options: invalidOptions }),
).to.throw(iconStringError);
});
it('should not require description, tags, or icon', () => {
const { description, tags, icon, ...validOptions } = options;
return expect(
createDapp.bind(null, { passphrase, options: validOptions }),
).not.to.throw();
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(undefined);
});
it('should use time.getTimeWithOffset with an offset of -10 seconds to calculate the timestamp', () => {
const offset = -10;
createDapp({ passphrase, options, timeOffset: offset });
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(offset);
});
describe('returned create dapp transaction', () => {
it('should be an object', () => {
return expect(createDappTransaction).to.be.an('object');
});
it('should have an id string', () => {
return expect(createDappTransaction)
.to.have.property('id')
.and.be.a('string');
});
it('should have type number equal to 5', () => {
return expect(createDappTransaction)
.to.have.property('type')
.and.be.a('number')
.and.equal(5);
});
it('should have amount string equal to 0', () => {
return expect(createDappTransaction)
.to.have.property('amount')
.and.be.a('string')
.and.equal('0');
});
it('should have fee string equal to 25 LSK', () => {
return expect(createDappTransaction)
.to.have.property('fee')
.and.be.a('string')
.and.equal(fee);
});
it('should have recipientId equal to empty string', () => {
return expect(createDappTransaction)
.to.have.property('recipientId')
.and.equal('');
});
it('should have senderPublicKey hex string equal to sender public key', () => {
return expect(createDappTransaction)
.to.have.property('senderPublicKey')
.and.be.hexString.and.equal(publicKey);
});
it('should have timestamp number equal to result of time.getTimeWithOffset', () => {
return expect(createDappTransaction)
.to.have.property('timestamp')
.and.be.a('number')
.and.equal(timeWithOffset);
});
it('should have signature hex string', () => {
return expect(createDappTransaction).to.have.property('signature').and
.be.hexString;
});
it('should not have the second signature property', () => {
return expect(createDappTransaction).not.to.have.property(
'signSignature',
);
});
it('should have asset', () => {
return expect(createDappTransaction).to.have.property('asset').and.not
.be.empty;
});
describe('dapps asset', () => {
let asset: DappAsset;
beforeEach(() => {
asset = createDappTransaction.asset;
});
it('should be object', () => {
return expect(createDappTransaction.asset)
.to.have.property('dapp')
.and.be.an('object');
});
it('should have a category number equal to provided category', () => {
return expect(asset.dapp)
.to.have.property('category')
.and.be.a('number')
.and.equal(options.category);
});
it('should have a name string equal to provided name', () => {
return expect(asset.dapp)
.to.have.property('name')
.and.be.a('string')
.and.equal(options.name);
});
it('should have a description string equal to provided description', () => {
return expect(asset.dapp)
.to.have.property('description')
.and.be.a('string')
.and.equal(options.description);
});
it('should have a tags string equal to provided tags', () => {
return expect(asset.dapp)
.to.have.property('tags')
.and.be.a('string')
.and.equal(options.tags);
});
it('should have a type number equal to provided type', () => {
return expect(asset.dapp)
.to.have.property('type')
.and.be.a('number')
.and.equal(options.type);
});
it('should have a link string equal to provided link', () => {
return expect(asset.dapp)
.to.have.property('link')
.and.be.a('string')
.and.equal(options.link);
});
it('should have an icon string equal to provided icon', () => {
return expect(asset.dapp)
.to.have.property('icon')
.and.be.a('string')
.and.equal(options.icon);
});
});
});
});
describe('with first and second passphrase', () => {
beforeEach(() => {
createDappTransaction = createDapp({
passphrase,
secondPassphrase,
options,
});
return Promise.resolve();
});
it('should have the second signature property as hex string', () => {
return expect(createDappTransaction).to.have.property('signSignature').and
.be.hexString;
});
});
describe('unsigned create dapp transaction', () => {
describe('when the create dapp transaction is created without a passphrase', () => {
beforeEach(() => {
createDappTransaction = createDapp({
options,
});
return Promise.resolve();
});
it('should have the type', () => {
return expect(createDappTransaction)
.to.have.property('type')
.equal(transactionType);
});
it('should have the amount', () => {
return expect(createDappTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the fee', () => {
return expect(createDappTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the recipient id', () => {
return expect(createDappTransaction)
.to.have.property('recipientId')
.equal('');
});
it('should have the sender public key', () => {
return expect(createDappTransaction)
.to.have.property('senderPublicKey')
.equal(undefined);
});
it('should have the timestamp', () => {
return expect(createDappTransaction).to.have.property('timestamp');
});
it('should have the asset with dapp with properties category, description, name, tags, type, link, icon', () => {
return expect(createDappTransaction)
.to.have.nested.property('asset.dapp')
.with.all.keys(
'category',
'description',
'name',
'tags',
'type',
'link',
'icon',
);
});
it('should not have the signature', () => {
return expect(createDappTransaction).not.to.have.property('signature');
});
it('should not have the id', () => {
return expect(createDappTransaction).not.to.have.property('id');
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/_global_hooks.ts
================================================
afterEach(() => {
return sandbox.restore();
});
================================================
FILE: packages/lisk-transactions/test/_setup.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import sinon from 'sinon';
import chai, { Assertion } from 'chai';
import 'chai/register-expect';
import sinonChai from 'sinon-chai';
process.env.NODE_ENV = 'test';
Assertion.addProperty('hexString', function handleAssert(
this: Chai.ChaiStatic,
) {
const actual = this._obj;
new Assertion(actual).to.be.a('string');
const expected = Buffer.from(actual, 'hex').toString('hex');
this.assert(
expected === actual,
'expected #{this} to be a hexString',
'expected #{this} not to be a hexString',
);
});
Assertion.addProperty('integer', function handleAssert(this: Chai.ChaiStatic) {
const actual = this._obj;
new Assertion(actual).to.be.a('number');
const expected = parseInt(actual, 10);
this.assert(
actual === expected,
'expected #{this} to be an integer',
'expected #{this} not to be an integer',
);
});
[sinonChai].forEach(plugin => chai.use(plugin));
global.sandbox = sinon.createSandbox({
useFakeTimers: true,
});
================================================
FILE: packages/lisk-transactions/test/constants.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
FIXED_POINT,
DAPP_FEE,
DELEGATE_FEE,
IN_TRANSFER_FEE,
OUT_TRANSFER_FEE,
MULTISIGNATURE_FEE,
SIGNATURE_FEE,
TRANSFER_FEE,
VOTE_FEE,
BYTESIZES,
} from '../src/constants';
describe('transactions constants module', () => {
it('FIXED_POINT to be an integer', () => {
return expect(FIXED_POINT).to.be.an.integer;
});
it('DAPP_FEE to be an integer', () => {
return expect(DAPP_FEE).to.be.an.integer;
});
it('DELEGATE_FEE to be an integer', () => {
return expect(DELEGATE_FEE).to.be.an.integer;
});
it('IN_TRANSFER_FEE to be an integer', () => {
return expect(IN_TRANSFER_FEE).to.be.an.integer;
});
it('OUT_TRANSFER_FEE to be an integer', () => {
return expect(OUT_TRANSFER_FEE).to.be.an.integer;
});
it('MULTISIGNATURE_FEE to be an integer', () => {
return expect(MULTISIGNATURE_FEE).to.be.an.integer;
});
it('SIGNATURE_FEE to be an integer', () => {
return expect(SIGNATURE_FEE).to.be.an.integer;
});
it('TRANSFER_FEE to be an integer', () => {
return expect(TRANSFER_FEE).to.be.an.integer;
});
it('VOTE_FEE to be an integer', () => {
return expect(VOTE_FEE).to.be.an.integer;
});
it('BYTESIZES.TYPE to be an integer', () => {
return expect(BYTESIZES.TYPE).to.be.an.integer;
});
it('BYTESIZES.TIMESTAMP to be an integer', () => {
return expect(BYTESIZES.TIMESTAMP).to.be.an.integer;
});
it('BYTESIZES.MULTISIGNATURE_PUBLICKEY to be an integer', () => {
return expect(BYTESIZES.MULTISIGNATURE_PUBLICKEY).to.be.an.integer;
});
it('BYTESIZES.RECIPIENT_ID to be an integer', () => {
return expect(BYTESIZES.RECIPIENT_ID).to.be.an.integer;
});
it('BYTESIZES.AMOUNT to be an integer', () => {
return expect(BYTESIZES.AMOUNT).to.be.an.integer;
});
it('BYTESIZES.SIGNATURE_TRANSACTION to be an integer', () => {
return expect(BYTESIZES.SIGNATURE_TRANSACTION).to.be.an.integer;
});
it('BYTESIZES.SECOND_SIGNATURE_TRANSACTION to be an integer', () => {
return expect(BYTESIZES.SECOND_SIGNATURE_TRANSACTION).to.be.an.integer;
});
it('BYTESIZES.DATA to be an integer', () => {
return expect(BYTESIZES.DATA).to.be.an.integer;
});
});
================================================
FILE: packages/lisk-transactions/test/create_signature_object.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
createSignatureObject,
SignatureObject,
} from '../src/create_signature_object';
describe('#createSignatureObject', () => {
const transaction = {
amount: '10',
recipientId: '8050281191221330746L',
senderId: '1050281191221330746L',
senderPublicKey:
'3358a1562f9babd523a768e700bb12ad58f230f84031055802dc0ea58cef1e1b',
timestamp: 59353522,
type: 0,
fee: '10000000',
recipientPublicKey: null,
asset: {},
signature:
'b84b95087c381ad25b5701096e2d9366ffd04037dcc941cd0747bfb0cf93111834a6c662f149018be4587e6fc4c9f5ba47aa5bbbd3dd836988f153aa8258e604',
id: '3694188453012384790',
};
const account = {
passphrase:
'love road panic horn cover grape nerve mechanic slice relax mobile salon',
publicKey:
'87696cfc48f5f5bd4ec2473615ac1618ffedfdc20005ae71a3d0dba209471c04',
};
const generatedSignature =
'8222dc7c26cc0ed649af71ebef5d292deb6ad029dadec0cf061b40e2ea9572d1b691e92302ac8cb64e5ea5f8fd846410c8fa033236c8930203ae3b7f3c6bd30c';
describe('when invalid transaction is used', () => {
it("should throw an Error when id doesn't exist", () => {
const { id, ...mutatedTransaction } = transaction;
return expect(
createSignatureObject.bind(
null,
mutatedTransaction,
account.passphrase,
),
).to.throw('Transaction ID is required to create a signature object.');
});
it('should throw an Error when sender public key is mutated', () => {
const mutatedTransaction = {
...transaction,
senderPublicKey:
'3358a1562f9babd523a768e700bb12ad58f230f84031055802dc0ea58cef1000',
};
return expect(
createSignatureObject.bind(
null,
mutatedTransaction,
account.passphrase,
),
).to.throw('Invalid transaction.');
});
it('should throw an Error when signature is mutated', () => {
const mutatedTransaction = {
...transaction,
signature:
'b84b95087c381ad25b5701096e2d9366ffd04037dcc941cd0747bfb0cf93111834a6c662f149018be4587e6fc4c9f5ba47aa5bbbd3dd836988f153aa8258e600',
};
return expect(
createSignatureObject.bind(
null,
mutatedTransaction,
account.passphrase,
),
).to.throw('Invalid transaction.');
});
});
describe('when valid transaction and invalid passphrase is used', () => {
it('should throw an Error if passphrase is number', () => {
const passphrase = 1;
return expect(
createSignatureObject.bind(null, transaction, passphrase),
).to.throw(
'Unsupported data format. Currently only Buffers or `hex` and `utf8` strings are supported.',
);
});
});
describe('when valid transaction and passphrase is used', () => {
let signatureObject: SignatureObject;
beforeEach(() => {
signatureObject = createSignatureObject(transaction, account.passphrase);
return Promise.resolve();
});
it('should have the same transaction id as the input', () => {
return expect(signatureObject.transactionId).to.equal(transaction.id);
});
it('should have the corresponding public key with the passphrase', () => {
return expect(signatureObject.publicKey).to.equal(account.publicKey);
});
it('should have non-empty hex string signature', () => {
return expect(signatureObject.signature).to.equal(generatedSignature);
});
});
});
================================================
FILE: packages/lisk-transactions/test/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as transaction from '../src';
describe('transaction', () => {
describe('exports', () => {
it('should have #transfer', () => {
return expect(transaction)
.to.have.property('transfer')
.and.be.a('function');
});
it('should have #registerSecondPassphrase', () => {
return expect(transaction)
.to.have.property('registerSecondPassphrase')
.and.be.a('function');
});
it('should have #registerDelegate', () => {
return expect(transaction)
.to.have.property('registerDelegate')
.and.be.a('function');
});
it('should have #castVotes', () => {
return expect(transaction)
.to.have.property('castVotes')
.and.be.a('function');
});
it('should have #registerMultisignature', () => {
return expect(transaction)
.to.have.property('registerMultisignature')
.and.be.a('function');
});
it('should have #createDapp', () => {
return expect(transaction)
.to.have.property('createDapp')
.and.be.a('function');
});
it('should have #createSignatureObject', () => {
return expect(transaction)
.to.have.property('createSignatureObject')
.and.be.a('function');
});
it('should have #utils', () => {
return expect(transaction)
.to.have.property('utils')
.and.be.an('object');
});
it('should have #constants', () => {
return expect(transaction)
.to.have.property('constants')
.and.be.an('object');
});
});
});
================================================
FILE: packages/lisk-transactions/test/mocha.opts
================================================
--recursive
--require ts-node/register
--require tsconfig-paths/register
--require source-map-support/register
--require ./test/_setup.ts
--file ./test/_global_hooks.ts
--watch-extensions ts
================================================
FILE: packages/lisk-transactions/test/tsconfig.json
================================================
{
"extends": "../tsconfig",
"compilerOptions": {
"baseUrl": ".",
"declaration": false,
"target": "es2017",
"typeRoots": ["../types", "../../../types", "../node_modules/@types"]
},
"include": ["../../../types/**/*", "./**/*"]
}
================================================
FILE: packages/lisk-transactions/test/utils/format.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
convertBeddowsToLSK,
convertLSKToBeddows,
prependPlusToPublicKeys,
prependMinusToPublicKeys,
} from '../../src/utils/format';
describe('format', () => {
describe('#convertBeddowsToLSK', () => {
it('should error if not given a string', () => {
return expect(convertBeddowsToLSK.bind(null, 12345678)).to.throw(
'Cannot convert non-string amount',
);
});
it('should error on 0.1', () => {
return expect(convertBeddowsToLSK.bind(null, '0.1')).to.throw(
'Beddows amount should not have decimal points',
);
});
it('should error on 9223372036854775808', () => {
return expect(
convertBeddowsToLSK.bind(null, '9223372036854775808'),
).to.throw('Beddows amount out of range');
});
it('should convert 100000000 to 1', () => {
return expect(convertBeddowsToLSK('100000000')).to.equal('1');
});
it('should convert 1 to 0.00000001', () => {
return expect(convertBeddowsToLSK('1')).to.equal('0.00000001');
});
it('should convert 10000000000000000 to 100000000', () => {
return expect(convertBeddowsToLSK('10000000000000000')).to.equal(
'100000000',
);
});
it('should convert 9223372036854775807 to 92233720368.54775807', () => {
return expect(convertBeddowsToLSK('9223372036854775807')).to.equal(
'92233720368.54775807',
);
});
});
describe('#convertLSKToBeddows', () => {
it('should error if not given a string', () => {
return expect(convertLSKToBeddows.bind(null, 12345678)).to.throw(
'Cannot convert non-string amount',
);
});
it('should error on 0.000000001', () => {
return expect(convertLSKToBeddows.bind(null, '0.000000001')).to.throw(
'LSK amount has too many decimal points',
);
});
it('should error on 92233720368.54775808', () => {
return expect(
convertLSKToBeddows.bind(null, '92233720368.54775808'),
).to.throw('LSK amount out of range');
});
it('should convert 1 to 100000000', () => {
return expect(convertLSKToBeddows('1')).to.equal('100000000');
});
it('should convert 0.00000001 to 1', () => {
return expect(convertLSKToBeddows('0.00000001')).to.equal('1');
});
it('should convert 100000000 to 10000000000000000', () => {
return expect(convertLSKToBeddows('100000000')).to.equal(
'10000000000000000',
);
});
it('should convert 92233720368.54775807 to 9223372036854775807', () => {
return expect(convertLSKToBeddows('92233720368.54775807')).to.equal(
'9223372036854775807',
);
});
});
describe('#prependPlusToPublicKeys', () => {
describe('Given an array of public keys', () => {
it('should append plus to each public key', () => {
const publicKeys = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
const expectedOutput = [
'+215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'+922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'+5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
return expect(prependPlusToPublicKeys(publicKeys)).to.be.eql(
expectedOutput,
);
});
});
});
describe('#prependMinusToPublicKeys', () => {
describe('Given an array of public keys', () => {
it('should append minus to each public key', () => {
const publicKeys = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
const expectedOutput = [
'-215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'-922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'-5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
return expect(prependMinusToPublicKeys(publicKeys)).to.be.eql(
expectedOutput,
);
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/get_transaction_bytes.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import BigNum from 'browserify-bignum';
import {
getTransactionBytes,
getAssetDataForTransferTransaction,
getAssetDataForRegisterSecondSignatureTransaction,
getAssetDataForRegisterDelegateTransaction,
getAssetDataForCastVotesTransaction,
getAssetDataForRegisterMultisignatureAccountTransaction,
getAssetDataForCreateDappTransaction,
getAssetDataForTransferIntoDappTransaction,
getAssetDataForTransferOutOfDappTransaction,
checkTransaction,
checkRequiredFields,
isValidValue,
} from '../../src/utils/get_transaction_bytes';
import {
TransferTransaction,
BaseTransaction,
MultiSignatureAsset,
} from '../../src/transaction_types';
const fixedPoint = 10 ** 8;
const defaultRecipient = '58191285901858109L';
const defaultSenderPublicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultSenderId = '18160565574430594874L';
const defaultSenderSecondPublicKey =
'0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
// Use (1<<62) + 3 to ensure the highest and the lowest bytes are set and contain different data.
// This exceeds the safe integer range of JavaScript numbers and thus is expressed as a string.
const defaultAmount = '10000000000000000';
const defaultNoAmount = '0';
const defaultTimestamp = 141738;
const defaultTransactionId = '13987348420913138422';
const defaultSignature =
'618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a';
const defaultSecondSignature =
'b00c4ad1988bca245d74435660a278bfe6bf2f5efa8bda96d927fabf8b4f6fcfdcb2953f6abacaa119d6880987a55dea0e6354bc8366052b45fa23145522020f';
const defaultAppId = '1234213';
const defaultDelegateUsername = 'MyDelegateUsername';
describe('getTransactionBytes module', () => {
describe('#getTransactionBytes', () => {
describe('transfer transaction, type 0', () => {
let defaultTransaction: BaseTransaction;
beforeEach(() => {
defaultTransaction = {
type: 0,
fee: (0.1 * fixedPoint).toString(),
amount: defaultAmount,
recipientId: defaultRecipient,
timestamp: defaultTimestamp,
asset: {},
senderPublicKey: defaultSenderPublicKey,
senderId: defaultSenderId,
signature: defaultSignature,
id: defaultTransactionId,
};
return Promise.resolve();
});
it('should return Buffer of type 0 (transfer LSK) transaction', () => {
const expectedBuffer = Buffer.from(
'00aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153d0000c16ff2862300618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(defaultTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
it('should return Buffer of type 0 (transfer LSK) with data', () => {
const transferTransaction: TransferTransaction = {
...defaultTransaction,
asset: {
data: 'Hello Lisk! Some data in here!...',
},
};
const expectedBuffer = Buffer.from(
'00aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153d0000c16ff286230048656c6c6f204c69736b2120536f6d65206461746120696e2068657265212e2e2e618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(transferTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
it('should throw on type 0 with too much data', () => {
const maxDataLength = 64;
const transferTransaction: TransferTransaction = {
...defaultTransaction,
asset: {
data: new Array(maxDataLength + 1).fill('1').join(''),
},
};
return expect(
getTransactionBytes.bind(null, transferTransaction),
).to.throw('Transaction asset data exceeds size of 64.');
});
it('should throw on type 0 with an amount that is too small', () => {
const amount = -1;
const transaction = {
...defaultTransaction,
amount,
};
return expect(getTransactionBytes.bind(null, transaction)).to.throw(
'Transaction amount must not be negative.',
);
});
it('should throw on type 0 with an amount that is too large', () => {
const amount = BigNum.fromBuffer(
Buffer.from(new Array(8).fill(255)),
).plus(1);
const transaction = {
...defaultTransaction,
amount,
};
return expect(getTransactionBytes.bind(null, transaction)).to.throw(
'Transaction amount is too large.',
);
});
it('should return Buffer of transaction with second signature', () => {
const transaction = {
...defaultTransaction,
signSignature: defaultSecondSignature,
};
const expectedBuffer = Buffer.from(
'00aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153d0000c16ff2862300618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0ab00c4ad1988bca245d74435660a278bfe6bf2f5efa8bda96d927fabf8b4f6fcfdcb2953f6abacaa119d6880987a55dea0e6354bc8366052b45fa23145522020f',
'hex',
);
const transactionBytes = getTransactionBytes(transaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
it('should return Buffer from multisignature type 0 (transfer LSK) transaction', () => {
const multiSignatureTransaction = {
type: 0,
amount: '1000',
fee: (1 * fixedPoint).toString(),
recipientId: defaultRecipient,
senderPublicKey: defaultSenderPublicKey,
requesterPublicKey:
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
timestamp: defaultTimestamp,
asset: {},
signatures: [],
signature: defaultSignature,
id: defaultTransactionId,
};
const expectedBuffer = Buffer.from(
'00aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae095d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153de803000000000000618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(multiSignatureTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
it('should return Buffer of type 0 (transfer LSK) with additional properties', () => {
const transaction = {
...defaultTransaction,
skip: false,
};
const expectedBuffer = Buffer.from(
'00aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153d0000c16ff2862300618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(transaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
it('should throw on missing required parameter type', () => {
const { type, ...defaultTransactionClone } = defaultTransaction;
expect(
getTransactionBytes.bind(null, defaultTransactionClone),
).to.throw(`type is a required parameter.`);
});
it('should throw on missing required parameter timestamp', () => {
const { timestamp, ...defaultTransactionClone } = defaultTransaction;
expect(
getTransactionBytes.bind(null, defaultTransactionClone),
).to.throw(`timestamp is a required parameter.`);
});
it('should throw on missing required parameter senderPublicKey', () => {
const {
senderPublicKey,
...defaultTransactionClone
} = defaultTransaction;
expect(
getTransactionBytes.bind(null, defaultTransactionClone),
).to.throw(`senderPublicKey is a required parameter.`);
});
it('should throw on missing required parameter amount', () => {
const { amount, ...defaultTransactionClone } = defaultTransaction;
expect(
getTransactionBytes.bind(null, defaultTransactionClone),
).to.throw(`amount is a required parameter.`);
});
});
describe('signature transaction, type 1', () => {
const signatureTransaction = {
type: 1,
amount: defaultNoAmount,
fee: (5 * fixedPoint).toString(),
recipientId: null,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: { signature: { publicKey: defaultSenderSecondPublicKey } },
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer of type 1 (register second signature) transaction', () => {
const expectedBuffer = Buffer.from(
'01aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09000000000000000000000000000000000401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(signatureTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
describe('delegate registration transaction, type 2', () => {
const delegateRegistrationTransaction = {
type: 2,
amount: defaultNoAmount,
fee: (25 * fixedPoint).toString(),
recipientId: null,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: { delegate: { username: defaultDelegateUsername } },
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer of type 2 (register delegate) transaction', () => {
const expectedBuffer = Buffer.from(
'02aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09000000000000000000000000000000004d7944656c6567617465557365726e616d65618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(
delegateRegistrationTransaction,
);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
describe('vote transaction, type 3', () => {
const voteTransaction = {
type: 3,
amount: '0',
fee: (1 * fixedPoint).toString(),
recipientId: defaultRecipient,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: {
votes: [
`+${defaultSenderPublicKey}`,
`+${defaultSenderSecondPublicKey}`,
],
},
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer of type 3 (vote) transaction', () => {
const expectedBuffer = Buffer.from(
'03aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153d00000000000000002b356430333661383538636538396638343434393137363265623839653262666264353061346130613064613635386534623236323862323562313137616530392b30343031633861633966323964656439653165346435623662343330353163623235623232663237633762376233353039323136316538353139343666383266618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(voteTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
describe('multisignature transaction, type 4', () => {
const createMultiSignatureTransaction = {
type: 4,
amount: '0',
fee: (15 * fixedPoint).toString(),
recipientId: null,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: {
multisignature: {
min: 2,
lifetime: 5,
keysgroup: [
`+${defaultSenderPublicKey}`,
`+${defaultSenderSecondPublicKey}`,
],
},
},
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer from type 4 (register multisignature) transaction', () => {
const expectedBuffer = Buffer.from(
'04aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae090000000000000000000000000000000002052b356430333661383538636538396638343434393137363265623839653262666264353061346130613064613635386534623236323862323562313137616530392b30343031633861633966323964656439653165346435623662343330353163623235623232663237633762376233353039323136316538353139343666383266618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(
createMultiSignatureTransaction,
);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
describe('dapp transaction, type 5', () => {
const dappTransaction = {
type: 5,
amount: '0',
fee: (25 * fixedPoint).toString(),
recipientId: null,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: {
dapp: {
category: 0,
name: 'Lisk Guestbook',
description: 'The official Lisk guestbook',
tags: 'guestbook message sidechain',
type: 0,
link: 'https://github.com/MaxKK/guestbookDapp/archive/master.zip',
icon:
'https://raw.githubusercontent.com/MaxKK/guestbookDapp/master/icon.png',
},
},
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer of type 5 (register dapp) transaction', () => {
const expectedBuffer = Buffer.from(
'05aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09000000000000000000000000000000004c69736b204775657374626f6f6b546865206f6666696369616c204c69736b206775657374626f6f6b6775657374626f6f6b206d6573736167652073696465636861696e68747470733a2f2f6769746875622e636f6d2f4d61784b4b2f6775657374626f6f6b446170702f617263686976652f6d61737465722e7a697068747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f4d61784b4b2f6775657374626f6f6b446170702f6d61737465722f69636f6e2e706e670000000000000000618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(dappTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
describe('inTransfer transaction, type 6', () => {
const inTransferTransction = {
type: 6,
amount: defaultAmount,
fee: (1 * fixedPoint).toString(),
recipientId: null,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: { inTransfer: { dappId: defaultAppId } },
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer of type 6 (dapp inTransfer) transaction', () => {
const expectedBuffer = Buffer.from(
'06aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900000000000000000000c16ff286230031323334323133618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(inTransferTransction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
describe('outTransfer transaction, type 7', () => {
const outTransferTransaction = {
type: 7,
amount: defaultAmount,
fee: (1 * fixedPoint).toString(),
recipientId: defaultRecipient,
senderPublicKey: defaultSenderPublicKey,
timestamp: defaultTimestamp,
asset: {
outTransfer: {
dappId: defaultAppId,
transactionId: defaultTransactionId,
},
},
signature: defaultSignature,
id: defaultTransactionId,
};
it('should return Buffer of type 7 (dapp outTransfer) transaction', () => {
const expectedBuffer = Buffer.from(
'07aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153d0000c16ff2862300313233343231333133393837333438343230393133313338343232618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
const transactionBytes = getTransactionBytes(outTransferTransaction);
return expect(transactionBytes).to.be.eql(expectedBuffer);
});
});
});
describe('getTransactionBytes functions', () => {
describe('#checkRequiredFields', () => {
const arrayToCheck = ['OneValue', 'SecondValue', 'ThirdValue'];
it('should accept array and object to check for required fields', () => {
const objectParameter = {
OneValue: '1',
SecondValue: '2',
ThirdValue: '3',
};
return expect(checkRequiredFields(arrayToCheck, objectParameter)).to.be
.true;
});
it('should throw on missing value', () => {
const objectParameter = {
OneValue: '1',
SecondValue: '2',
};
return expect(
checkRequiredFields.bind(null, arrayToCheck, objectParameter),
).to.throw('ThirdValue is a required parameter.');
});
});
describe('#getAssetDataForTransferTransaction', () => {
const defaultEmptyBuffer = Buffer.alloc(0);
it('should return Buffer for data asset', () => {
const expectedBuffer = Buffer.from('my data input', 'utf8');
const assetDataBuffer = getAssetDataForTransferTransaction({
data: 'my data input',
});
return expect(assetDataBuffer).to.be.eql(expectedBuffer);
});
it('should return empty Buffer for no asset data', () => {
const assetDataBuffer = getAssetDataForTransferTransaction({});
return expect(assetDataBuffer).to.be.eql(defaultEmptyBuffer);
});
});
describe('#getAssetDataForRegisterSecondSignatureTransaction', () => {
it('should return Buffer for signature asset', () => {
const expectedBuffer = Buffer.from(defaultSenderPublicKey, 'hex');
const assetSignaturesPublicKeyBuffer = getAssetDataForRegisterSecondSignatureTransaction(
{
signature: {
publicKey: defaultSenderPublicKey,
},
},
);
return expect(assetSignaturesPublicKeyBuffer).to.be.eql(expectedBuffer);
});
it('should throw on missing publicKey in the signature asset', () => {
return expect(
getAssetDataForRegisterSecondSignatureTransaction.bind(null, {
signature: {},
}),
).to.throw('publicKey is a required parameter.');
});
});
describe('#getAssetDataForRegisterDelegateTransaction', () => {
it('should return Buffer for delegate asset', () => {
const expectedBuffer = Buffer.from(defaultDelegateUsername, 'utf8');
const assetDelegateUsernameBuffer = getAssetDataForRegisterDelegateTransaction(
{
delegate: {
username: defaultDelegateUsername,
},
},
);
return expect(assetDelegateUsernameBuffer).to.be.eql(expectedBuffer);
});
it('should throw on missing username in the delegate asset', () => {
return expect(
getAssetDataForRegisterDelegateTransaction.bind(null, {
delegate: {},
}),
).to.throw('username is a required parameter.');
});
});
describe('#getAssetDataForCastVotesTransaction', () => {
it('should return Buffer for votes asset', () => {
const votesAsset = {
votes: [
`+${defaultSenderPublicKey}`,
`+${defaultSenderSecondPublicKey}`,
],
};
const expectedBuffer = Buffer.from(
`+${defaultSenderPublicKey}+${defaultSenderSecondPublicKey}`,
'utf8',
);
const assetVoteBuffer = getAssetDataForCastVotesTransaction(votesAsset);
return expect(assetVoteBuffer).to.be.eql(expectedBuffer);
});
it('should throw on missing votes in the vote asset', () => {
return expect(
getAssetDataForCastVotesTransaction.bind(null, { votes: {} }),
).to.throw('votes parameter must be an Array.');
});
});
describe('#getAssetDataForRegisterMultisignatureAccountTransaction', () => {
const min = 2;
const lifetime = 5;
const keysgroup = ['+123456789', '-987654321'];
let multisignatureAsset: MultiSignatureAsset;
beforeEach(() => {
multisignatureAsset = {
multisignature: {
min,
lifetime,
keysgroup,
},
};
return Promise.resolve();
});
it('should return Buffer for multisignature asset', () => {
const minBuffer = Buffer.alloc(1, min);
const lifetimeBuffer = Buffer.alloc(1, lifetime);
const keysgroupBuffer = Buffer.from('+123456789-987654321', 'utf8');
const expectedBuffer = Buffer.concat([
minBuffer,
lifetimeBuffer,
keysgroupBuffer,
]);
const multisignatureBuffer = getAssetDataForRegisterMultisignatureAccountTransaction(
multisignatureAsset,
);
return expect(multisignatureBuffer).to.be.eql(expectedBuffer);
});
it('should throw on missing required parameter min', () => {
const { min, ...multisigAsset } = multisignatureAsset.multisignature;
expect(
getAssetDataForRegisterMultisignatureAccountTransaction.bind(null, {
multisignature: multisigAsset,
}),
).to.throw(`min is a required parameter.`);
});
it('should throw on missing required parameter lifetime', () => {
const {
lifetime,
...multisigAsset
} = multisignatureAsset.multisignature;
expect(
getAssetDataForRegisterMultisignatureAccountTransaction.bind(null, {
multisignature: multisigAsset,
}),
).to.throw(`lifetime is a required parameter.`);
});
it('should throw on missing required parameter keysgroup', () => {
const {
keysgroup,
...multisigAsset
} = multisignatureAsset.multisignature;
expect(
getAssetDataForRegisterMultisignatureAccountTransaction.bind(null, {
multisignature: multisigAsset,
}),
).to.throw(`keysgroup is a required parameter.`);
});
});
describe('#getAssetDataForCreateDappTransaction', () => {
const defaultCategory = 0;
const defaultDappName = 'Lisk Guestbook';
const defaultDescription = 'The official Lisk guestbook';
const defaultTags = 'guestbook message sidechain';
const defaultType = 0;
const defaultLink =
'https://github.com/MaxKK/guestbookDapp/archive/master.zip';
const defaultIcon =
'https://raw.githubusercontent.com/MaxKK/guestbookDapp/master/icon.png';
const dappNameBuffer = Buffer.from('4c69736b204775657374626f6f6b', 'hex');
const dappDescriptionBuffer = Buffer.from(
'546865206f6666696369616c204c69736b206775657374626f6f6b',
'hex',
);
const dappTagsBuffer = Buffer.from(
'6775657374626f6f6b206d6573736167652073696465636861696e',
'hex',
);
const dappLinkBuffer = Buffer.from(
'68747470733a2f2f6769746875622e636f6d2f4d61784b4b2f6775657374626f6f6b446170702f617263686976652f6d61737465722e7a6970',
'hex',
);
const dappIconBuffer = Buffer.from(
'68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f4d61784b4b2f6775657374626f6f6b446170702f6d61737465722f69636f6e2e706e67',
'hex',
);
const dappTypeBuffer = Buffer.alloc(4, defaultType);
const dappCategoryBuffer = Buffer.alloc(4, defaultCategory);
it('should return Buffer for create dapp asset', () => {
const dappAsset = {
dapp: {
category: defaultCategory,
name: defaultDappName,
description: defaultDescription,
tags: defaultTags,
type: defaultType,
link: defaultLink,
icon: defaultIcon,
},
};
const expectedBuffer = Buffer.concat([
dappNameBuffer,
dappDescriptionBuffer,
dappTagsBuffer,
dappLinkBuffer,
dappIconBuffer,
dappTypeBuffer,
dappCategoryBuffer,
]);
const dappBuffer = getAssetDataForCreateDappTransaction(dappAsset);
return expect(dappBuffer).to.be.eql(expectedBuffer);
});
it('should throw for create dapp asset without required fields', () => {
const dapp: { readonly [key: string]: string | number } = {
category: defaultCategory,
name: defaultDappName,
description: defaultDescription,
tags: defaultTags,
type: defaultType,
link: defaultLink,
icon: defaultIcon,
};
const requiredProperties = ['name', 'link', 'type', 'category'];
return requiredProperties.forEach(parameter => {
const { [parameter]: deletedValue, ...dappClone } = dapp;
expect(
getAssetDataForCreateDappTransaction.bind(null, {
dapp: dappClone,
}),
).to.throw(`${parameter} is a required parameter.`);
});
});
});
describe('#getAssetDataForTransferIntoDappTransaction', () => {
it('should return Buffer for dappIn asset', () => {
const dappInAsset = {
inTransfer: {
dappId: defaultAppId,
},
};
const expectedBuffer = Buffer.from(defaultAppId, 'utf8');
const dappInTransferBuffer = getAssetDataForTransferIntoDappTransaction(
dappInAsset,
);
return expect(dappInTransferBuffer).to.be.eql(expectedBuffer);
});
it('should throw on missing votes in the vote asset', () => {
return expect(
getAssetDataForTransferIntoDappTransaction.bind(null, {
inTransfer: {},
}),
).to.throw('dappId is a required parameter.');
});
});
describe('#getAssetDataForTransferOutOfDappTransaction', () => {
it('should return Buffer for dappOut asset', () => {
const dappOutAsset = {
outTransfer: {
dappId: defaultAppId,
transactionId: defaultTransactionId,
},
};
const dappIdBuffer = Buffer.from(defaultAppId, 'utf8');
const transactionIdBuffer = Buffer.from(defaultTransactionId);
const expectedBuffer = Buffer.concat([
dappIdBuffer,
transactionIdBuffer,
]);
const dappOutTransferBuffer = getAssetDataForTransferOutOfDappTransaction(
dappOutAsset,
);
return expect(dappOutTransferBuffer).to.be.eql(expectedBuffer);
});
it('should throw on missing votes in the vote asset', () => {
return expect(
getAssetDataForTransferOutOfDappTransaction.bind(null, {
outTransfer: {},
}),
).to.throw('dappId is a required parameter.');
});
});
describe('#checkTransaction', () => {
const maxDataLength = 64;
let defaultTransaction: BaseTransaction;
beforeEach(() => {
defaultTransaction = {
type: 0,
fee: (0.1 * fixedPoint).toString(),
amount: defaultAmount,
recipientId: defaultRecipient,
timestamp: defaultTimestamp,
asset: {},
senderPublicKey: defaultSenderPublicKey,
senderId: defaultSenderId,
signature: defaultSignature,
id: defaultTransactionId,
};
return Promise.resolve();
});
it('should throw on too many data in transfer asset', () => {
const transaction = {
...defaultTransaction,
asset: {
data: new Array(maxDataLength + 1).fill('1').join(''),
},
};
return expect(checkTransaction.bind(null, transaction)).to.throw(
'Transaction asset data exceeds size of 64.',
);
});
it('should return true on asset data exactly at max data length', () => {
const transaction = {
...defaultTransaction,
asset: {
data: new Array(maxDataLength).fill('1').join(''),
},
};
return expect(checkTransaction(transaction)).to.be.true;
});
});
describe('#isInvalidValue', () => {
it('should return false on invalid values', () => {
const allInvalidValues = [NaN, false, undefined];
return allInvalidValues.forEach(value => {
const invalid = isValidValue(value);
expect(invalid).to.be.false;
});
});
it('should return true on valid values', () => {
const exampleValidValues = ['123', 123, { 1: 2, 3: 4 }, [1, 2, 3]];
return exampleValidValues.forEach(value => {
const valid = isValidValue(value);
expect(valid).to.be.true;
});
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/get_transaction_hash.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { getTransactionHash } from '../../src/utils';
import { BaseTransaction } from '../../src/transaction_types';
import * as getTransactionBytesModule from '../../src/utils/get_transaction_bytes';
describe('#getTransactionHash', () => {
let defaultTransactionBytes;
let transaction: BaseTransaction;
let result: Buffer;
beforeEach(() => {
defaultTransactionBytes = Buffer.from(
'00aa2902005d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae0900cebcaa8d34153de803000000000000618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
'hex',
);
sandbox
.stub(getTransactionBytesModule, 'getTransactionBytes')
.returns(defaultTransactionBytes);
transaction = {
type: 0,
amount: '1000',
fee: '0',
recipientId: '58191285901858109L',
timestamp: 141738,
asset: {},
senderPublicKey:
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
signature:
'618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
id: '13987348420913138422',
};
result = getTransactionHash(transaction);
return Promise.resolve();
});
it('should get transaction bytes', () => {
return expect(
getTransactionBytesModule.getTransactionBytes,
).to.be.calledWithExactly(transaction);
});
it('should return a hash for a transaction object as a Buffer', () => {
const expected = Buffer.from(
'f60a26da470b1dc233fd526ed7306c1d84836f9e2ecee82c9ec47319e0910474',
'hex',
);
return expect(result).to.be.eql(expected);
});
});
================================================
FILE: packages/lisk-transactions/test/utils/get_transaction_id.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as cryptography from '@liskhq/lisk-cryptography';
import { getTransactionId } from '../../src/utils';
import { BaseTransaction } from '../../src/transaction_types';
// Require is used for stubbing
const utils = require('../../src/utils');
describe('#getTransactionId', () => {
const defaultPublicKey =
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09';
const defaultTransactionId = '13987348420913138422';
const defaultTransactionHash = Buffer.from(
'f60a26da470b1dc233fd526ed7306c1d84836f9e2ecee82c9ec47319e0910474',
'hex',
);
const defaultAmount = '1000';
const defaultTimestamp = 141738;
const defaultRecipientId = '58191285901858109L';
const defaultSignature =
'618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a';
beforeEach(() => {
sandbox.stub(cryptography, 'hash').returns(defaultTransactionHash);
return sandbox.stub(utils, 'getTransactionBytes');
});
it('should return an id of 13987348420913138422 for a transaction', () => {
const transaction: BaseTransaction = {
type: 0,
amount: defaultAmount,
fee: '0',
recipientId: defaultRecipientId,
timestamp: defaultTimestamp,
asset: {},
senderPublicKey: defaultPublicKey,
signature: defaultSignature,
};
const id = getTransactionId(transaction);
return expect(id).to.be.equal(defaultTransactionId);
});
});
================================================
FILE: packages/lisk-transactions/test/utils/index.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
checkPublicKeysForDuplicates,
convertBeddowsToLSK,
convertLSKToBeddows,
getTimeFromBlockchainEpoch,
getTimeWithOffset,
getTransactionBytes,
getTransactionHash,
getTransactionId,
prepareTransaction,
prependMinusToPublicKeys,
prependPlusToPublicKeys,
signRawTransaction,
signTransaction,
multiSignTransaction,
verifyTransaction,
validateAddress,
validateAmount,
isValidInteger,
validateKeysgroup,
validatePublicKey,
validatePublicKeys,
validateTransaction,
} from '../../src/utils';
describe('transaction utils', () => {
describe('exports', () => {
it('should have checkPublicKeysForDuplicates', () => {
return expect(checkPublicKeysForDuplicates).to.be.a('function');
});
it('should have convertBeddowsToLSK', () => {
return expect(convertBeddowsToLSK).to.be.a('function');
});
it('should have convertLSKToBeddows', () => {
return expect(convertLSKToBeddows).to.be.a('function');
});
it('should have getTimeFromBlockchainEpoch', () => {
return expect(getTimeFromBlockchainEpoch).to.be.a('function');
});
it('should have getTimeWithOffset', () => {
return expect(getTimeWithOffset).to.be.a('function');
});
it('should have getTransactionBytes', () => {
return expect(getTransactionBytes).to.be.a('function');
});
it('should have getTransactionHash', () => {
return expect(getTransactionHash).to.be.a('function');
});
it('should have getTransactionId', () => {
return expect(getTransactionId).to.be.a('function');
});
it('should have prepareTransaction', () => {
return expect(prepareTransaction).to.be.a('function');
});
it('should have prependMinusToPublicKeys', () => {
return expect(prependMinusToPublicKeys).to.be.a('function');
});
it('should have prependPlusToPublicKeys', () => {
return expect(prependPlusToPublicKeys).to.be.a('function');
});
it('should have signRawTransaction', () => {
return expect(signRawTransaction).to.be.a('function');
});
it('should have signTransaction', () => {
return expect(signTransaction).to.be.a('function');
});
it('should have multiSignTransaction', () => {
return expect(multiSignTransaction).to.be.a('function');
});
it('should have verifyTransaction', () => {
return expect(verifyTransaction).to.be.a('function');
});
it('should have validateAddress', () => {
return expect(validateAddress).to.be.a('function');
});
it('should have validateAmount', () => {
return expect(validateAmount).to.be.a('function');
});
it('should have isValidInteger', () => {
return expect(isValidInteger).to.be.a('function');
});
it('should have validateKeysgroup', () => {
return expect(validateKeysgroup).to.be.a('function');
});
it('should have validatePublicKey', () => {
return expect(validatePublicKey).to.be.a('function');
});
it('should have validatePublicKeys', () => {
return expect(validatePublicKeys).to.be.a('function');
});
it('should have validateTransaction', () => {
return expect(validateTransaction).to.be.a('function');
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/prepare_transaction.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { prepareTransaction } from '../../src/utils/prepare_transaction';
import { getTimeWithOffset } from '../../src/utils/time';
import {
BaseTransaction,
PartialTransaction,
} from '../../src/transaction_types';
describe('#prepareTransaction', () => {
const passphrase = 'secret';
const keys = {
privateKey:
'2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
publicKey:
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
};
const signature =
'a00835fe0ad89d8b8a26cc3ffa8238d89bd38999f39d712fe8745707c8e18ea70337a7dfde725fddaa858dd64843170de3e481f54438b8aad734b0e75bbad706';
const secondPassphrase = 'second secret';
const secondSignature =
'08ce78b2382c396596cc38ea8b9dbc2df62f0d919ddc817070902eeaf1b93ca17ced0766bb4e10f565ae9e55f673691d966dea45e60922fd2685556b441ffb0e';
const id = '8330167589806376997';
const defaultTransaction = {
type: 0,
amount: (10e8).toString(),
timestamp: 10,
senderPublicKey: keys.publicKey,
asset: {},
};
let inputTransaction: PartialTransaction;
let preparedTransaction: BaseTransaction;
beforeEach(() => {
inputTransaction = { ...defaultTransaction };
return Promise.resolve();
});
describe('without type', () => {
it('should throw an error when it is not transaction', () => {
const { type, ...invalidTransaction } = inputTransaction;
return expect(
prepareTransaction.bind(null, invalidTransaction, passphrase),
).to.throw('Invalid transaction to process');
});
});
describe('without signature', () => {
beforeEach(() => {
preparedTransaction = prepareTransaction(inputTransaction);
return Promise.resolve();
});
it('should not mutate the original transaction', () => {
return expect(inputTransaction).to.eql(defaultTransaction);
});
it('should not add a signature to a transaction', () => {
return expect(preparedTransaction.signature).to.be.undefined;
});
it('should not add an id to a transaction', () => {
return expect(preparedTransaction.id).to.be.undefined;
});
it('should add timestamp with the offset', () => {
const { timestamp, ...transactionWithoutTimestamp } = inputTransaction;
const currentTimestamp = getTimeWithOffset();
preparedTransaction = prepareTransaction(
transactionWithoutTimestamp,
undefined,
undefined,
50,
);
return expect(preparedTransaction.timestamp).to.be.gt(currentTimestamp);
});
});
describe('without second signature', () => {
beforeEach(() => {
preparedTransaction = prepareTransaction(inputTransaction, passphrase);
return Promise.resolve();
});
it('should not mutate the original transaction', () => {
return expect(inputTransaction).to.eql(defaultTransaction);
});
it('should add a signature to a transaction', () => {
return expect(preparedTransaction)
.to.have.property('signature')
.and.be.hexString.and.equal(signature);
});
it('should add an id to a transaction', () => {
return expect(preparedTransaction)
.to.have.property('id')
.and.match(/^[0-9]+$/)
.and.equal(id);
});
});
describe('with second signature', () => {
beforeEach(() => {
preparedTransaction = prepareTransaction(
inputTransaction,
passphrase,
secondPassphrase,
);
return Promise.resolve();
});
it('should not mutate the original transaction', () => {
return expect(inputTransaction).to.eql(defaultTransaction);
});
it('should add a second signature to a transaction if a second passphrase is provided', () => {
return expect(preparedTransaction)
.to.have.property('signSignature')
.and.be.hexString.and.equal(secondSignature);
});
it('should not add a second signature to a type 1 transaction', () => {
inputTransaction = Object.assign({}, defaultTransaction, {
type: 1,
asset: {
signature: {
publicKey: keys.publicKey,
},
},
});
preparedTransaction = prepareTransaction(
inputTransaction,
passphrase,
secondPassphrase,
);
return expect(preparedTransaction).not.to.have.property('signSignature');
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/sign_and_verify.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import * as cryptography from '@liskhq/lisk-cryptography';
import {
signTransaction,
multiSignTransaction,
verifyTransaction,
} from '../../src/utils';
// The list of valid transactions was created with lisk-js v0.5.1
// using the below mentioned passphrases.
import fixtureTransactions from '../../fixtures/transactions.json';
import {
PartialTransaction,
BaseTransaction,
} from '../../src/transaction_types';
import * as getTransactionHashModule from '../../src/utils/get_transaction_hash';
// Require is used for stubbing
const validTransactions = fixtureTransactions as ReadonlyArray;
describe('signAndVerify module', () => {
describe('signAndVerify transaction utils', () => {
const defaultPassphrase =
'minute omit local rare sword knee banner pair rib museum shadow juice';
const defaultPublicKey =
'7ef45cd525e95b7a86244bbd4eb4550914ad06301013958f4dd64d32ef7bc588';
const defaultSecondPublicKey =
'0401c8ac9f29ded9e1e4d5b6b43051cb25b22f27c7b7b35092161e851946f82f';
const defaultSignature =
'bb3f2d12d098c59a0af03bb1157eeb7bc7141b21cea57861c4eac72a7c55f122b5befb1391c3f8509b562fa748fdc7359f6e6051526d979915157c5bcba34e01';
const defaultSecondSignature =
'897090248c0ecdad749d869ddeae59e5029bdbe4806da92d82d6eb7142b624011f4302941db184a2e70bd29a6adac5ce0b4cf780af893db2f504375bdef6850b';
const defaultHash = Buffer.from(
'c62214460d66eeb1d9db3fb708e31040d2629fbdb6c93887c5eb0f3243912f91',
'hex',
);
let defaultTransaction: PartialTransaction;
let cryptoSignDataStub: sinon.SinonStub;
let cryptoVerifyDataStub: sinon.SinonStub;
let getTransactionHashStub: sinon.SinonStub;
beforeEach(() => {
defaultTransaction = {
type: 0,
amount: '1000',
recipientId: '58191285901858109L',
timestamp: 141738,
asset: {},
id: '13987348420913138422',
senderPublicKey: defaultPublicKey,
};
cryptoSignDataStub = sandbox
.stub(cryptography, 'signData')
.returns(defaultSignature);
cryptoVerifyDataStub = sandbox
.stub(cryptography, 'verifyData')
.returns(true);
getTransactionHashStub = sandbox
.stub(getTransactionHashModule, 'getTransactionHash')
.returns(defaultHash);
return Promise.resolve();
});
describe('#signTransaction', () => {
let transaction: BaseTransaction;
let signature: string;
beforeEach(() => {
transaction = { ...defaultTransaction } as BaseTransaction;
signature = signTransaction(transaction, defaultPassphrase);
return Promise.resolve();
});
it('should get the transaction hash', () => {
return expect(getTransactionHashStub).to.be.calledWithExactly(
transaction,
);
});
it('should sign the transaction hash with the passphrase', () => {
return expect(cryptoSignDataStub).to.be.calledWithExactly(
defaultHash,
defaultPassphrase,
);
});
it('should return the signature', () => {
return expect(signature).to.be.equal(defaultSignature);
});
});
describe('#multiSignTransaction', () => {
const defaultMultisignatureHash = Buffer.from(
'd43eed9049dd8f35106c720669a1148b2c6288d9ea517b936c33a1d84117a760',
'hex',
);
let multiSignatureTransaction: BaseTransaction;
let signature: string;
beforeEach(() => {
multiSignatureTransaction = {
type: 0,
amount: '1000',
recipientId: '58191285901858109L',
timestamp: 141738,
asset: {},
senderPublicKey:
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
signature:
'618a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
signSignature:
'508a54975212ead93df8c881655c625544bce8ed7ccdfe6f08a42eecfb1adebd051307be5014bb051617baf7815d50f62129e70918190361e5d4dd4796541b0a',
id: '13987348420913138422',
} as BaseTransaction;
getTransactionHashStub.returns(defaultMultisignatureHash);
signature = multiSignTransaction(
multiSignatureTransaction,
defaultPassphrase,
);
return Promise.resolve();
});
it('should remove the signature and second signature before getting transaction hash', () => {
expect(getTransactionHashStub.args[0]).not.to.have.property(
'signature',
);
return expect(getTransactionHashStub.args[0]).not.to.have.property(
'signSignature',
);
});
it('should sign the transaction hash with the passphrase', () => {
return expect(cryptoSignDataStub).to.be.calledWithExactly(
defaultMultisignatureHash,
defaultPassphrase,
);
});
it('should return the signature', () => {
return expect(signature).to.be.equal(defaultSignature);
});
});
describe('#verifyTransaction', () => {
let transaction: BaseTransaction;
describe('with a single signed transaction', () => {
beforeEach(() => {
transaction = {
...defaultTransaction,
signature: defaultSignature,
} as BaseTransaction;
return Promise.resolve();
});
it('should throw if attempting to verify without a secondPublicKey', () => {
const { signature, ...invalidTransaction } = transaction;
return expect(
verifyTransaction.bind(null, invalidTransaction),
).to.throw('Cannot verify transaction without signature.');
});
it('should remove the signature before getting transaction hash', () => {
verifyTransaction(transaction);
return expect(getTransactionHashStub.args[0]).not.to.have.property(
'signature',
);
});
it('should verify the transaction using the hash, the signature and the public key', () => {
verifyTransaction(transaction);
return expect(cryptoVerifyDataStub).to.be.calledWithExactly(
defaultHash,
defaultSignature,
defaultPublicKey,
);
});
it('should return false for an invalid signature', () => {
cryptoVerifyDataStub.returns(false);
const verification = verifyTransaction(transaction);
return expect(verification).to.be.false;
});
it('should return true for a valid signature', () => {
const verification = verifyTransaction(transaction);
return expect(verification).to.be.true;
});
});
describe('with a second signed transaction', () => {
beforeEach(() => {
transaction = {
...defaultTransaction,
signature: defaultSignature,
signSignature: defaultSecondSignature,
} as BaseTransaction;
return getTransactionHashStub
.onFirstCall()
.returns(
Buffer.from(
'951bb4580dcb6a412de28844e0e06439c5c51dfea2a16730fd94ff20e355f1bd',
'hex',
),
);
});
it('should throw if attempting to verify without a secondPublicKey', () => {
const { signature, ...invalidTransaction } = transaction;
return expect(
verifyTransaction.bind(null, invalidTransaction),
).to.throw('Cannot verify transaction without signature.');
});
it('should throw if attempting to verify without a secondPublicKey', () => {
return expect(verifyTransaction.bind(null, transaction)).to.throw(
'Cannot verify signSignature without secondPublicKey.',
);
});
it('should remove the second signature before getting the first transaction hash', () => {
verifyTransaction(transaction, defaultSecondPublicKey);
return expect(
getTransactionHashStub.firstCall.args[0],
).not.to.have.property('signSignature');
});
it('should remove the first signature before getting the second transaction hash', () => {
verifyTransaction(transaction, defaultSecondPublicKey);
return expect(
getTransactionHashStub.secondCall.args[0],
).not.to.have.property('signature');
});
it('should return false for an invalid second signature', () => {
cryptoVerifyDataStub.returns(false);
const verification = verifyTransaction(
transaction,
defaultSecondPublicKey,
);
return expect(verification).to.be.false;
});
it('should return false for an invalid first signature', () => {
cryptoVerifyDataStub.onSecondCall().returns(false);
getTransactionHashStub
.onFirstCall()
.returns(
Buffer.from(
'aef147521619556572f204585332aac247dc2b024cb975518d847e4587bab756',
'hex',
),
);
const verification = verifyTransaction(
transaction,
defaultSecondPublicKey,
);
return expect(verification).to.be.false;
});
it('should return true for a valid signature', () => {
const verification = verifyTransaction(
transaction,
defaultSecondPublicKey,
);
return expect(verification).to.be.true;
});
});
});
});
describe('integration sign and verify', () => {
describe('given a set of transactions', () => {
describe('#signTransaction', () => {
describe('given a passphrase and a second passphrase', () => {
const passphrase =
'wagon stock borrow episode laundry kitten salute link globe zero feed marble';
const secondPassphrase =
'trouble float modify long valve group ozone possible remove dirt bicycle riot';
describe('when tested on the first signature', () => {
it('should create the correct signature', () => {
return validTransactions.forEach(transaction => {
const { signature, signSignature, ...rawTx } = transaction;
return expect(signTransaction(rawTx, passphrase)).to.be.equal(
signature,
);
});
});
});
describe('when tested on the second signature', () => {
it('should create the correct signature', () => {
return validTransactions.forEach(transaction => {
const { signSignature } = transaction;
if (signSignature) {
const { signSignature, ...rawTx } = transaction;
return expect(
signTransaction(rawTx, secondPassphrase),
).to.be.equal(signSignature);
}
return true;
});
});
});
});
});
describe('#verifyTransaction', () => {
describe('when executed', () => {
const secondPublicKey =
'f9666bfed9ef2ff52a04408f22f2bfffaa81384c9433463697330224f10032a4';
it('should verify all the transactions', () => {
return validTransactions.forEach(transaction => {
return expect(verifyTransaction(transaction, secondPublicKey)).to
.be.true;
});
});
});
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/sign_raw_transaction.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { signRawTransaction } from '../../src/utils/sign_raw_transaction';
import {
BaseTransaction,
PartialTransaction,
} from '../../src/transaction_types';
import * as time from '../../src/utils/time';
describe('#signRawTransaction', () => {
const timeWithOffset = 38350076;
const amount = '100';
const recipientId = '123456789L';
const timestamp = 12345;
const fee = '10000000';
const type = 0;
const asset = {};
let getTimeWithOffsetStub: sinon.SinonStub;
beforeEach(() => {
getTimeWithOffsetStub = sandbox
.stub(time, 'getTimeWithOffset')
.returns(timeWithOffset);
return Promise.resolve();
});
describe('given a raw transaction', () => {
let transaction: PartialTransaction;
beforeEach(() => {
transaction = {
amount,
recipientId,
timestamp,
type,
fee,
recipientPublicKey: null,
asset,
};
return Promise.resolve();
});
describe('given a passphrase', () => {
const passphrase =
'wagon stock borrow episode laundry kitten salute link globe zero feed marble';
const senderPublicKey =
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f';
const senderId = '16313739661670634666L';
const signature =
'd09288d22a1ac860f625db950340cd26e435d0d98a00ffb92d55c16b76d83ed4fd1acf974c28c9dede8fb15a49ccaddb6325f4e750d968e515e1f0d90e0fb30d';
const transactionId = '9248517814265997446';
describe('when executed', () => {
let signedTransaction: BaseTransaction;
let signingProperties;
beforeEach(() => {
signingProperties = {
passphrase,
transaction,
};
signedTransaction = signRawTransaction(signingProperties);
return Promise.resolve();
});
it('should have the type', () => {
return expect(signedTransaction)
.to.have.property('type')
.equal(type);
});
it('should have the amount', () => {
return expect(signedTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the asset', () => {
return expect(signedTransaction)
.to.have.property('asset')
.eql(asset);
});
it('should have the senderPublicKey', () => {
return expect(signedTransaction)
.to.have.property('senderPublicKey')
.equal(senderPublicKey);
});
it('should have the senderId', () => {
return expect(signedTransaction)
.to.have.property('senderId')
.equal(senderId);
});
it('should have the recipientId', () => {
return expect(signedTransaction)
.to.have.property('recipientId')
.equal(recipientId);
});
it('should have the fee', () => {
return expect(signedTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the updated timestamp', () => {
return expect(signedTransaction)
.to.have.property('timestamp')
.be.equal(timeWithOffset);
});
it('should have the senderSecondPublicKey', () => {
return expect(signedTransaction)
.to.have.property('senderSecondPublicKey')
.equal(undefined);
});
it('should have the signature', () => {
return expect(signedTransaction)
.to.have.property('signature')
.be.equal(signature);
});
it('should have the id', () => {
return expect(signedTransaction)
.to.have.property('id')
.be.equal(transactionId);
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(
undefined,
);
});
});
describe('given a second passphrase', () => {
const secondPassphrase =
'guitar couch salmon subject review urban heavy autumn crush tribe home plunge';
const senderSecondPublicKey =
'c465d74511c2bfd136cf9764172acd3c1514fa7ad76475e03bc91cf679757a5c';
const signSignature =
'31ef8fcf4e1815def245ad32d0d0e3e86993a4029c41e8ca1dc2674c9794d31cefc2226ac539dea8049c7085fdcb29768389b96104ac05a0ddabfb8b523af409';
const secondSignedTransactionId = '5702597341252953087';
describe('when executed', () => {
let signedTransaction: BaseTransaction;
let signingProperties;
beforeEach(() => {
signingProperties = {
passphrase,
transaction,
secondPassphrase,
};
signedTransaction = signRawTransaction(signingProperties);
return Promise.resolve();
});
it('should have the type', () => {
return expect(signedTransaction)
.to.have.property('type')
.equal(type);
});
it('should have the amount', () => {
return expect(signedTransaction)
.to.have.property('amount')
.equal(amount);
});
it('should have the asset', () => {
return expect(signedTransaction)
.to.have.property('asset')
.eql(asset);
});
it('should have the senderPublicKey', () => {
return expect(signedTransaction)
.to.have.property('senderPublicKey')
.equal(senderPublicKey);
});
it('should have the senderId', () => {
return expect(signedTransaction)
.to.have.property('senderId')
.equal(senderId);
});
it('should have the recipientId', () => {
return expect(signedTransaction)
.to.have.property('recipientId')
.equal(recipientId);
});
it('should have the fee', () => {
return expect(signedTransaction)
.to.have.property('fee')
.equal(fee);
});
it('should have the updated timestamp', () => {
return expect(signedTransaction)
.to.have.property('timestamp')
.be.equal(timeWithOffset);
});
it('should have the senderSecondPublicKey', () => {
return expect(signedTransaction)
.to.have.property('senderSecondPublicKey')
.equal(senderSecondPublicKey);
});
it('should have the signature', () => {
return expect(signedTransaction)
.to.have.property('signature')
.be.eql(signature);
});
it('should have the second signature', () => {
return expect(signedTransaction)
.to.have.property('signSignature')
.be.equal(signSignature);
});
it('should have the id', () => {
return expect(signedTransaction)
.to.have.property('id')
.be.equal(secondSignedTransactionId);
});
it('should use time.getTimeWithOffset to calculate the timestamp', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(
undefined,
);
});
});
describe('given an offset', () => {
const timeOffset = 1000;
let signingProperties;
describe('when executed', () => {
beforeEach(() => {
signingProperties = {
passphrase,
transaction,
secondPassphrase,
timeOffset,
};
return signRawTransaction(signingProperties);
});
it('should calculate the time with the time offset', () => {
return expect(getTimeWithOffsetStub).to.be.calledWithExactly(
timeOffset,
);
});
});
});
});
});
});
describe('given a signed transaction', () => {
const senderPublicKey =
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f';
const senderId = '16313739661670634666L';
const signature =
'd09288d22a1ac860f625db950340cd26e435d0d98a00ffb92d55c16b76d83ed4fd1acf974c28c9dede8fb15a49ccaddb6325f4e750d968e515e1f0d90e0fb30d';
const transactionId = '9248517814265997446';
const updatedSignerPassphrase =
'wagon stock borrow episode laundry kitten salute link globe zero feed';
const updatedSignerPublicKey =
'798974780475d8d7d6c6c9bb3dabf10efb16b7b380469223ee3ecc711c8e1396';
const updatedSignerAddress = '5752844829611395697L';
const updatedSignerSignature =
'647ca03394d0fefeeaa018e6943feb61c0ec64f3110ab96fe87564f1c915a40f25ac19324802684de87cdc5a0947f774d8b0ae78f9144635996d0450bcd5760c';
const updatedSignerId = '9495608349801955934';
let transaction: PartialTransaction;
beforeEach(() => {
transaction = {
amount,
recipientId,
senderPublicKey,
timestamp,
type,
fee,
senderId,
signature,
id: transactionId,
recipientPublicKey: null,
asset,
};
return Promise.resolve();
});
describe('when executed', () => {
let signedTransaction: BaseTransaction;
let signingProperties;
beforeEach(() => {
signingProperties = {
passphrase: updatedSignerPassphrase,
transaction,
};
signedTransaction = signRawTransaction(signingProperties);
return Promise.resolve();
});
it('should sign the transaction', () => {
return expect(signedTransaction).to.be.ok;
});
it('should have the updated senderPublicKey', () => {
return expect(signedTransaction)
.to.have.property('senderPublicKey')
.equal(updatedSignerPublicKey);
});
it('should have the updated senderId', () => {
return expect(signedTransaction)
.to.have.property('senderId')
.equal(updatedSignerAddress);
});
it('should have the updated transactionId', () => {
return expect(signedTransaction)
.to.have.property('id')
.equal(updatedSignerId);
});
it('should have the updated signature', () => {
return expect(signedTransaction)
.to.have.property('signature')
.equal(updatedSignerSignature);
});
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/time.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import {
getTimeFromBlockchainEpoch,
getTimeWithOffset,
} from '../../src/utils/time';
describe('time module', () => {
const nowRealTime = new Date(1464109220000);
const nowEpochTime = 20;
beforeEach(() => {
return sandbox.useFakeTimers(nowRealTime.getTime());
});
afterEach(() => {
return sandbox.clock.restore();
});
describe('#getTimeFromBlockchainEpoch', () => {
it('should return current time as number', () => {
const time = getTimeFromBlockchainEpoch();
return expect(time).to.be.equal(nowEpochTime);
});
it('should return epoch time for provided time as number, equal to 10', () => {
const realTime = 1464109210001;
const time = getTimeFromBlockchainEpoch(realTime);
return expect(time).to.be.equal(10);
});
});
describe('#getTimeWithOffset', () => {
it('should get time with undefined offset', () => {
const time = getTimeWithOffset();
return expect(time).to.be.equal(nowEpochTime);
});
it('should get time with positive offset', () => {
const offset = 3;
const time = getTimeWithOffset(offset);
return expect(time).to.be.equal(23);
});
it('should get time with negative offset', () => {
const offset = -3;
const time = getTimeWithOffset(offset);
return expect(time).to.be.equal(17);
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/validation/validate_transaction.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import fixtures from '../../../fixtures/transactions.json';
import invalidFixtures from '../../../fixtures/invalid_transactions.json';
import { validateTransaction } from '../../../src/utils/validation/validate_transaction';
import { PartialTransaction } from '../../../src/transaction_types';
import { ErrorObject } from 'ajv';
describe('validateTransaction', () => {
describe('#validateTransaction', () => {
describe('when fixtures provided', () => {
it('should be all valid for the fixtures', () => {
return fixtures.forEach((tx: unknown) => {
const { valid, errors } = validateTransaction(
tx as PartialTransaction,
);
expect(valid).to.be.true;
expect(errors).to.be.undefined;
});
});
});
describe('when transaction does not contain type', () => {
const invalidTransaction = {
amount: '0',
fee: '10000000',
recipientId: 'recipientID',
senderPublicKey:
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f',
timestamp: 54196078,
asset: {},
signature:
'4c8a3bfaacfab18a7ef34ce8d7176ea2701dfd7221a1c95ecbc1cce778bbccdb7cbbe1a87b3e9e47330f1cae6665c4a44666e132aa324de9a5ab9b6a1e2b1d0c',
id: '18066659039293493823',
};
it('should throw an error', () => {
return expect(
validateTransaction.bind(null, invalidTransaction),
).to.throw(Error, 'Transaction type is required.');
});
});
describe('when invalid fixtures provided', () => {
it('should be all invalid for the invalid fixtures (except type 6 and 7)', () => {
return invalidFixtures
.filter((tx: PartialTransaction) => tx.type !== 6 && tx.type !== 7)
.forEach((tx: PartialTransaction) => {
const { valid, errors } = validateTransaction(tx);
expect(valid).to.be.false;
expect(errors).not.to.be.undefined;
});
});
it('should throw an unsupported transaction type error for type 6 and 7', () => {
return invalidFixtures
.filter((tx: PartialTransaction) => tx.type === 6 || tx.type === 7)
.forEach((tx: PartialTransaction) => {
expect(validateTransaction.bind(null, tx)).to.throw(
Error,
'Unsupported transaction type.',
);
});
});
});
describe('when the transaction contains invalid data in merged schema', () => {
const invalidTransaction = {
type: 0,
amount: '0',
fee: '10000000',
recipientId: 'recipientID',
senderPublicKey:
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f',
timestamp: 54196078,
asset: {},
signature:
'4c8a3bfaacfab18a7ef34ce8d7176ea2701dfd7221a1c95ecbc1cce778bbccdb7cbbe1a87b3e9e47330f1cae6665c4a44666e132aa324de9a5ab9b6a1e2b1d0c',
id: '18066659039293493823',
};
it('should not include $merge error when the merged schema has error', () => {
const { valid, errors } = validateTransaction(invalidTransaction);
expect(valid).to.be.false;
expect(errors).not.to.be.undefined;
const errorsArray = errors as ReadonlyArray;
expect(errorsArray[0].dataPath).to.equal('.amount');
expect(errorsArray[1].dataPath).to.equal('.recipientId');
return expect(errors).to.have.length(2);
});
});
});
describe('#getTransactionSchemaValidator', () => {
const type6Tx = {
type: 6,
amount: '166413',
fee: '10000000',
recipientId: '',
senderPublicKey:
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f',
timestamp: 54196078,
asset: { inTransfer: { dappId: '1000000' } },
signature:
'f2b1a66d9bd8ae0c1b3404fe397a11bd696e5aea274e6a8d9fea2f976503d006b8ca65484daf2498f854a0c0109b924b653a8d6ba31a568cb70727b7d3472902',
id: '9501694969515165251',
};
const type7Tx = {
type: 7,
amount: '835151',
fee: '10000000',
recipientId: '1859190791819301L',
senderPublicKey:
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f',
timestamp: 54196079,
asset: {
outTransfer: { dappId: '614143983', transactionId: '749591467' },
},
signature:
'646cd6be9f385bfa4f914b66a675a77080a3c1093278cfbca16d3d7fbf768350c9a7e270a8e5a72347e2792d3cfc770f3a3bb9ea542c300cba3976f34bd040e',
};
it('should throw an error when type 6 transaction is provided', () => {
return expect(validateTransaction.bind(null, type6Tx)).to.throw(
Error,
'Unsupported transaction type.',
);
});
it('should throw an error when type 7 transaction is provided', () => {
return expect(validateTransaction.bind(null, type7Tx)).to.throw(
Error,
'Unsupported transaction type.',
);
});
});
describe('#validateMultiTransaction', () => {
const invalidMultiTransaction = {
type: 4,
amount: '0',
fee: '3000000000',
recipientId: '',
senderPublicKey:
'c094ebee7ec0c50ebee32918655e089f6e1a604b83bcaa760293c61e0f18ab6f',
timestamp: 54196078,
asset: {
multisignature: {
min: 6,
lifetime: 1,
keysgroup: [
'+e64df51060a2ce43f91b24ae75cc83f1866f9fead2ca2420cf3df153e6368a97',
'+4ef26ed51f4b82134b16f25a2556bed98a0b3963a17c0d2f0fa87f67cc6f29fe',
'+818d34925549e0aea67f1b82190c3e288b1c66de95ce699c2f5c87f1e622012c',
'+a2eece2bf0ee74e492939ac84723646270bfefab84914a5cf68baffd9bb84858',
'+46f3ec44dbcffe28c6bcd4eb494ce24ceea51677eb67005bdd4dd3202db55251',
],
},
},
signature:
'4c8a3bfaacfab18a7ef34ce8d7176ea2701dfd7221a1c95ecbc1cce778bbccdb7cbbe1a87b3e9e47330f1cae6665c4a44666e132aa324de9a5ab9b6a1e2b1d0c',
id: '18066659039293493823',
};
it('should be invalid when min is greater than the keysgroup', () => {
const { valid, errors } = validateTransaction(invalidMultiTransaction);
expect(valid).to.be.false;
expect(errors).not.to.be.undefined;
const errorsArray = errors as ReadonlyArray;
expect(errorsArray[0].dataPath).to.equal('.asset.multisignature.min');
return expect(errorsArray[0].message).to.equal(
'.asset.multisignature.min cannot be greater than .asset.multisignature.keysgroup.length',
);
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/validation/validation.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import * as cryptography from '@liskhq/lisk-cryptography';
import { expect } from 'chai';
import BigNum from 'browserify-bignum';
import {
checkPublicKeysForDuplicates,
validatePublicKey,
validatePublicKeys,
validateKeysgroup,
validateAddress,
validateAmount,
validateTransferAmount,
validateFee,
isGreaterThanMaxTransactionAmount,
isGreaterThanZero,
isGreaterThanMaxTransactionId,
isNumberString,
isValidInteger,
} from '../../../src/utils/validation/validation';
describe('validation', () => {
describe('#validatePublicKey', () => {
describe('Given a hex string with odd length', () => {
const invalidHexPublicKey =
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bc';
it('should throw an error', () => {
return expect(
validatePublicKey.bind(null, invalidHexPublicKey),
).to.throw('Argument must have a valid length of hex string.');
});
});
describe('Given a hex string with additional non-hex characters', () => {
const invalidHexPublicKey =
'12345678123456781234567812345678123456781234567812345678123456gg';
it('should throw an error', () => {
return expect(
validatePublicKey.bind(null, invalidHexPublicKey),
).to.throw('Argument must be a valid hex string.');
});
});
describe('Given a too long public key', () => {
const tooLongPublicKey =
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca12';
it('should throw an error', () => {
return expect(validatePublicKey.bind(null, tooLongPublicKey)).to.throw(
'Public key 215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca12 length differs from the expected 32 bytes for a public key.',
);
});
});
describe('Given a too short public key', () => {
const tooShortPublicKey =
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452b';
it('should throw an error', () => {
return expect(validatePublicKey.bind(null, tooShortPublicKey)).to.throw(
'Public key 215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452b length differs from the expected 32 bytes for a public key.',
);
});
});
describe('Given a valid public key', () => {
const publicKey =
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca';
it('should return true', () => {
return expect(validatePublicKey(publicKey)).to.be.true;
});
});
describe('Given a valid public key with only numeric characters', () => {
const publicKey =
'1234567812345678123456781234567812345678123456781234567812345678';
it('should return true', () => {
return expect(validatePublicKey(publicKey)).to.be.true;
});
});
});
describe('#validatePublicKeys', () => {
describe('Given an array of public keys with one invalid public key', () => {
const publicKeys = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bc',
];
it('should throw an error', () => {
return expect(validatePublicKeys.bind(null, publicKeys)).to.throw(
'Argument must have a valid length of hex string.',
);
});
});
describe('Given an array of valid public keys', () => {
const publicKeys = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'1234567812345678123456781234567812345678123456781234567812345678',
];
it('should return true', () => {
return expect(validatePublicKeys(publicKeys)).to.be.true;
});
});
});
describe('#validateKeysgroup', () => {
let keysgroup: ReadonlyArray;
describe('Given a keysgroup with three public keys', () => {
beforeEach(() => {
keysgroup = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
return Promise.resolve();
});
it('the validated keysgroup should return true', () => {
return expect(validateKeysgroup(keysgroup)).to.be.true;
});
});
describe('Given an empty keysgroup', () => {
beforeEach(() => {
keysgroup = [];
return Promise.resolve();
});
it('should throw the error', () => {
return expect(validateKeysgroup.bind(null, keysgroup)).to.throw(
'Expected between 1 and 15 public keys in the keysgroup.',
);
});
});
describe('Given a keysgroup with 17 public keys', () => {
beforeEach(() => {
keysgroup = new Array(17)
.fill(0)
.map(
(_: number, index: number) =>
cryptography.getPrivateAndPublicKeyFromPassphrase(
index.toString(),
).publicKey,
);
return Promise.resolve();
});
it('should throw the error', () => {
return expect(validateKeysgroup.bind(null, keysgroup)).to.throw(
'Expected between 1 and 15 public keys in the keysgroup.',
);
});
});
});
describe('#checkPublicKeysForDuplicates', () => {
describe('Given an array of public keys without duplication', () => {
const publicKeys = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
];
it('should return true', () => {
return expect(checkPublicKeysForDuplicates(publicKeys)).to.be.true;
});
});
describe('Given an array of public keys with duplication', () => {
const publicKeys = [
'215b667a32a5cd51a94c9c2046c11fffb08c65748febec099451e3b164452bca',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
'922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa',
];
it('should throw an error', () => {
return expect(
checkPublicKeysForDuplicates.bind(null, publicKeys),
).to.throw(
'Duplicated public key: 922fbfdd596fa78269bbcadc67ec2a1cc15fc929a19c462169568d7a3df1a1aa.',
);
});
});
});
describe('#validateAddress', () => {
describe('Given valid addresses', () => {
const addresses = [
'13133549779353512613L',
'18446744073709551615L',
'1L',
];
it('should return true', () => {
return addresses.forEach(address => {
return expect(validateAddress(address)).to.be.true;
});
});
});
describe('Given an address that is too short', () => {
const address = 'L';
it('should throw an error', () => {
return expect(validateAddress.bind(null, address)).to.throw(
'Address length does not match requirements. Expected between 2 and 22 characters.',
);
});
});
describe('Given an address that is too long', () => {
const address = '12345678901234567890123L';
it('should throw an error', () => {
return expect(validateAddress.bind(null, address)).to.throw(
'Address length does not match requirements. Expected between 2 and 22 characters.',
);
});
});
describe('Given an address without L at the end', () => {
const address = '1234567890';
it('should throw an error', () => {
return expect(validateAddress.bind(null, address)).to.throw(
'Address format does not match requirements. Expected "L" at the end.',
);
});
});
describe('Given an address that includes `.`', () => {
const address = '14.15133512790761431L';
it('should throw an error', () => {
return expect(validateAddress.bind(null, address)).to.throw(
'Address format does not match requirements. Address includes invalid character: `.`.',
);
});
});
describe('Given an address that is out of range', () => {
const address = '18446744073709551616L';
it('should throw an error', () => {
return expect(validateAddress.bind(null, address)).to.throw(
'Address format does not match requirements. Address out of maximum range.',
);
});
});
describe('Given an address that has leading zeros', () => {
const address = '00015133512790761431L';
it('should throw an error', () => {
return expect(validateAddress.bind(null, address)).to.throw(
"Address string format does not match it's number representation.",
);
});
});
});
describe('#validateAmount', () => {
it('should return true when amount is 0', () => {
return expect(validateAmount('0')).to.be.true;
});
});
describe('#validateTransferAmount', () => {
it('should return false is amount is 0', () => {
return expect(validateTransferAmount('0')).to.be.false;
});
it('should return true when amount is a number greater than 0 and less than maximum transaction amount', () => {
return expect(validateTransferAmount('100')).to.be.true;
});
});
describe('#validateFee', () => {
it('should return false is amount is 0', () => {
return expect(validateFee('0')).to.be.false;
});
it('should return true when amount is a number greater than 0 and less than maximum transaction amount', () => {
return expect(validateFee('100')).to.be.true;
});
});
describe('#isGreaterThanZero', () => {
it('should return false when amount is 0', () => {
return expect(isGreaterThanZero(new BigNum('0'))).to.be.false;
});
it('should return true when amount is greater than 0', () => {
return expect(
isGreaterThanZero(new BigNum('9223372036854775808987234289782357')),
).to.be.true;
});
});
describe('#isGreaterThanMaxTransactionAmount', () => {
it('should return false when amount is less than maximum transaction amount', () => {
return expect(
isGreaterThanMaxTransactionAmount(new BigNum('9223372036854775807')),
).to.be.false;
});
it('should return true when amount is more than maximum transaction amount', () => {
return expect(
isGreaterThanMaxTransactionAmount(new BigNum('9223372036854775808')),
).to.be.true;
});
});
describe('#isGreaterThanMaxTransactionId', () => {
it('should return false when id is less than 8 bytes integer maximum', () => {
return expect(
isGreaterThanMaxTransactionId(new BigNum('18446744073709551615')),
).to.be.false;
});
it('should return true when id is more than 8 bytes integer maximum', () => {
return expect(
isGreaterThanMaxTransactionId(new BigNum('18446744073709551616')),
).to.be.true;
});
});
describe('#isNumberString', () => {
it('should return false when number is not string', () => {
const invalidFunction = isNumberString as (input: any) => boolean;
return expect(invalidFunction(1)).to.be.false;
});
it('should return false when string contains non number', () => {
return expect(isNumberString('12345abc68789')).to.be.false;
});
it('should return true when string contains only number', () => {
return expect(isNumberString('1234568789')).to.be.true;
});
});
describe('#isValidInteger', () => {
it('should return false when string was provided', () => {
return expect(isValidInteger('1234')).to.be.false;
});
it('should return false when float was provided', () => {
return expect(isValidInteger(123.4)).to.be.false;
});
it('should return true when integer was provided', () => {
return expect(isValidInteger(6)).to.be.true;
});
it('should return true when negative integer was provided', () => {
return expect(isValidInteger(-6)).to.be.true;
});
});
});
================================================
FILE: packages/lisk-transactions/test/utils/validation/validator.ts
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
import { expect } from 'chai';
import { validator } from '../../../src/utils/validation/validator';
import { ValidateFunction } from 'ajv';
describe('validator', () => {
const baseSchemaId = 'test/schema';
before(() => {
const baseSchema = {
$id: baseSchemaId,
type: 'object',
};
return validator.addSchema(baseSchema);
});
describe('signature', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'signature',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid signature is provided', () => {
return expect(
validate({
target:
'd5bdb0577f53fe5d79009c42facdf295a555e9542c851ec49feef1680f824a1ebae00733d935f078c3ef621bc20ee88d81390f9c97f75adb14731504861b7304',
}),
).to.be.true;
});
it('should validate to false when non-hex character is in the signature', () => {
return expect(
validate({
target:
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzf295a555e9542c851ec49feef1680f824a1ebae00733d935f078c3ef621bc20ee88d81390f9c97f75adb14731504861b7304',
}),
).to.be.false;
});
it('should validate to false when the signature is under 128 characters', () => {
return expect(
validate({
target:
'd5bdb0577f53fe5d79009c42facdf295a555e9542c851ec49feef1680f824a1ebae00733d935f078c3ef621bc20ee88d81390f9c97f75adb14731504861b730',
}),
).to.be.false;
});
it('should validate to false when the signature is over 128 characters', () => {
return expect(
validate({
target:
'd5bdb0577f53fe5d79009c42facdf295a555e9542c851ec49feef1680f824a1ebae00733d935f078c3ef621bc20ee88d81390f9c97f75adb14731504861b7304a',
}),
).to.be.false;
});
});
describe('id', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'id',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid id is provided', () => {
return expect(validate({ target: '3543510233978718399' })).to.be.true;
});
it('should validate to true when valid id with leading zeros is provided', () => {
return expect(validate({ target: '00123' })).to.be.true;
});
it('should validate to false when number greater than maximum is provided', () => {
return expect(validate({ target: '18446744073709551616' })).to.be.false;
});
it('should validate to false when number is provided', () => {
return expect(validate({ target: 3543510233978718399 })).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('address', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'address',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid address is provided', () => {
return expect(validate({ target: '14815133512790761431L' })).to.be.true;
});
it('should validate to false when address with leading zeros is provided', () => {
return expect(validate({ target: '00015133512790761431L' })).to.be.false;
});
it('should validate to false when address including `.` is provided', () => {
return expect(validate({ target: '14.15133512790761431L' })).to.be.false;
});
it('should validate to false when number greater than maximum is provided', () => {
return expect(validate({ target: '18446744073709551616L' })).to.be.false;
});
it('should validate to false when the address does not end with "L"', () => {
return expect(validate({ target: '14815133512790761431X' })).to.be.false;
});
it('should validate to false when the address only contains numbers', () => {
return expect(validate({ target: '18446744073709551616' })).to.be.false;
});
it('should validate to false when the address is less than 2 characters', () => {
return expect(validate({ target: 'L' })).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('amount', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'amount',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid amount is provided', () => {
return expect(validate({ target: '0' })).to.be.true;
});
it('should validate to false when invalid amount with leading zeros is provided', () => {
return expect(validate({ target: '000001' })).to.be.false;
});
it('should validate to false when number greater than maximum is provided', () => {
return expect(validate({ target: '9223372036854775808' })).to.be.false;
});
it('should validate to false when decimal number is provided', () => {
return expect(validate({ target: '190.105310' })).to.be.false;
});
it('should validate to false when number is provided', () => {
return expect(validate({ target: 190105310 })).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('transfer amount', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'transferAmount',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid amount is provided', () => {
return expect(validate({ target: '100' })).to.be.true;
});
it('should validate to true when valid amount with leading zeros is provided', () => {
return expect(validate({ target: '000000100' })).to.be.true;
});
it('should validate to false when amount is 0', () => {
return expect(validate({ target: '0' })).to.be.false;
});
it('should validate to false when number greater than maximum is provided', () => {
return expect(validate({ target: '9223372036854775808' })).to.be.false;
});
it('should validate to false when decimal number is provided', () => {
return expect(validate({ target: '190.105310' })).to.be.false;
});
it('should validate to false when number is provided', () => {
return expect(validate({ target: 190105310 })).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('publicKey', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'publicKey',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid publicKey is provided', () => {
return expect(
validate({
target:
'05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.true;
});
it('should validate to false when non-hex character is in the publicKey', () => {
return expect(
validate({
target:
'zzzzze75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.false;
});
it('should validate to false when publicKey is shorter', () => {
return expect(
validate({
target:
'05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021',
}),
).to.be.false;
});
it('should validate to false when publicKey is longer', () => {
return expect(
validate({
target:
'05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b1',
}),
).to.be.false;
});
it('should validate to false when signed publicKey is provided', () => {
return expect(
validate({
target:
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b1',
}),
).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('signedPublicKey', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'signedPublicKey',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid + and publicKey is provided', () => {
return expect(
validate({
target:
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.true;
});
it('should validate to true when valid - and publicKey is provided', () => {
return expect(
validate({
target:
'-05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.true;
});
it('should validate to false when non-hex character is in the publicKey', () => {
return expect(
validate({
target:
'+zzzzze75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.false;
});
it('should validate to false when publicKey is shorter', () => {
return expect(
validate({
target:
'-05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021',
}),
).to.be.false;
});
it('should validate to false when publicKey is longer', () => {
return expect(
validate({
target:
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b1',
}),
).to.be.false;
});
it('should validate to false when non-signed publicKey is provided', () => {
return expect(
validate({
target:
'05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b1',
}),
).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('additionPublicKey', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'string',
format: 'additionPublicKey',
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when valid + and publicKey is provided', () => {
return expect(
validate({
target:
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.true;
});
it('should validate to false when valid - and publicKey is provided', () => {
return expect(
validate({
target:
'-05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.false;
});
it('should validate to false when non-hex character is in the publicKey', () => {
return expect(
validate({
target:
'+zzzzze75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
}),
).to.be.false;
});
it('should validate to false when publicKey is shorter', () => {
return expect(
validate({
target:
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021',
}),
).to.be.false;
});
it('should validate to false when publicKey is longer', () => {
return expect(
validate({
target:
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b1',
}),
).to.be.false;
});
it('should validate to false when non-signed publicKey is provided', () => {
return expect(
validate({
target:
'05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b1',
}),
).to.be.false;
});
it('should validate to false when it is empty', () => {
return expect(validate({ target: '' })).to.be.false;
});
});
describe('uniqueSignedPublicKeys', () => {
let validate: ValidateFunction;
beforeEach(() => {
validate = validator.compile({
$merge: {
source: { $ref: baseSchemaId },
with: {
properties: {
target: {
type: 'array',
uniqueSignedPublicKeys: true,
},
},
},
},
});
return Promise.resolve();
});
it('should validate to true when unique signedPublicKey is provided', () => {
return expect(
validate({
target: [
'-05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
'+278a9aecf13e324c42d73cae7e21e5efc1520afb1abcda084d086d24441ed2b4',
],
}),
).to.be.true;
});
it('should validate to false when publicKeys are duplicated without the sign', () => {
return expect(
validate({
target: [
'-05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
],
}),
).to.be.false;
});
it('should validate to false when publicKeys are duplicated with the same sign', () => {
return expect(
validate({
target: [
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
'+05e1ce75b98d6051030e4e416483515cf8360be1a1bd6d2c14d925700dae021b',
],
}),
).to.be.false;
});
});
});
================================================
FILE: packages/lisk-transactions/types/ajv-merge-patch/index.d.ts
================================================
/* tslint:disable:only-arrow-functions */
declare module 'ajv-merge-patch' {
export default function addKeywords(ajv: object): void;
}
================================================
FILE: packages/lisk-transactions/types/browserify-bignum/index.d.ts
================================================
/* tslint:disable:only-arrow-functions member-access readonly-keyword no-any */
///
declare module 'browserify-bignum' {
class BigNum {
/**
* Create a new BigNum from a Buffer.
*
* The default options are: {endian: 'big', size: 1}.
*/
static fromBuffer(buffer: Buffer, options?: BigNum.BufferOptions): BigNum;
/** Return true if num is identified as a BigNum instance. Otherwise, return false. */
static isBigNum(num: any): boolean;
/**
* Generate a probable prime of length bits.
*
* If safe is true, it will be a "safe" prime of the form p=2p'+1 where p' is also prime.
*/
static prime(bits: number, safe?: boolean): BigNum;
/** Create a new BigNum from n. */
constructor(n: number | BigNum);
/** Create a new BigNum from n and a base. */
constructor(n: string, base?: number);
/** Return a new BigNum with the absolute value of the instance. */
abs(): BigNum;
/** Return a new BigNum containing the instance value plus n. */
add(n: BigNum.BigNumCompatible): BigNum;
/** Return the number of bits used to represent the current BigNum. */
bitLength(): number;
/**
* Compare the instance value to n.
*
* Return a positive integer if > n, a negative integer if < n, and 0 if == n.
*/
cmp(n: BigNum.BigNumCompatible): number;
/** Return a new BigNum containing the instance value integrally divided by n. */
div(n: BigNum.BigNumCompatible): BigNum;
/** Return a boolean: whether the instance value is equal to n (== n). */
eq(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is greater than or equal to n (>= n). */
ge(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is greater than n (> n). */
gt(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is greater than n (>= n). */
gte(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
le(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is less than n (< n). */
lt(n: BigNum.BigNumCompatible): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
lte(n: BigNum.BigNumCompatible): boolean;
/** Return a new BigNum with the instance value modulo n. */
mod(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum containing the instance value multiplied by n. */
mul(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum with the negative of the instance value. */
neg(): BigNum;
/** Return a new BigNum containing the instance value plus n. */
plus(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum with the instance value raised to the nth power. */
pow(n: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum with the instance value raised to the nth power modulo m. */
powm(n: BigNum.BigNumCompatible, m: BigNum.BigNumCompatible): BigNum;
/** Return a new BigNum containing the instance value minus n. */
sub(n: BigNum.BigNumCompatible): BigNum;
/**
* Return a new Buffer with the data from the BigNum.
*
* The default options are: {endian: 'big', size: 1}.
*/
toBuffer(options?: BigNum.BufferOptions): Buffer;
/**
* Turn a BigNum into a Number.
*
* If the BigNum is too big you'll lose precision or you'll get ±Infinity.
*/
toNumber(): number;
/** Print out the BigNum instance in the requested base as a string. Default: base 10 */
toString(base?: number): string;
/** Print out the BigNum instance in the requested base as a string. Default: base 10 */
toString(base?: number): string;
}
export = BigNum;
namespace BigNum {
/** Anything that can be converted to BigNum. */
type BigNumCompatible = BigNum | number | string;
export interface BufferOptions {
/** Can be either 'big' or 'little'. Also accepts 1 for big and -1 for little. Doesn't matter when size = 1. */
endian: string | number;
/** Number of bytes per word, or 'auto' to flip entire Buffer. */
size: number | string;
}
/**
* Turn a BigNum into a Number.
*
* If the BigNum is too big you'll lose precision or you'll get ±Infinity.
*/
export function toNumber(n: BigNumCompatible): number;
/**
* Return a new Buffer with the data from the BigNum.
*
* The default options are: {endian: 'big', size: 1}.
*/
export function toBuffer(
n: BigNumCompatible,
options?: BufferOptions,
): Buffer;
/** Return a new BigNum containing the instance value plus n. */
export function add(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value plus n. */
export function plus(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value minus n. */
export function sub(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value multiplied by n. */
export function mul(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum containing the instance value integrally divided by n. */
export function div(
dividend: BigNumCompatible,
divisor: BigNumCompatible,
): BigNum;
/** Return a new BigNum with the absolute value of the instance. */
export function abs(n: BigNumCompatible): BigNum;
/** Return a new BigNum with the negative of the instance value. */
export function neg(n: BigNumCompatible): BigNum;
/**
* Compare the instance value to n.
*
* Return a positive integer if > n, a negative integer if < n, and 0 if == n.
*/
export function cmp(
left: BigNumCompatible,
right: BigNumCompatible,
): number;
/** Return a boolean: whether the instance value is greater than n (> n). */
export function gt(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is greater than or equal to n (>= n). */
export function gte(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is greater than or equal to n (>= n). */
export function ge(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is equal to n (== n). */
export function eq(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is less than n (< n). */
export function lt(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
export function lte(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a boolean: whether the instance value is less than or equal to n (<= n). */
export function le(
left: BigNumCompatible,
right: BigNumCompatible,
): boolean;
/** Return a new BigNum with the instance value modulo n. */
export function mod(
left: BigNumCompatible,
right: BigNumCompatible,
): BigNum;
/** Return a new BigNum with the instance value raised to the nth power. */
export function pow(
base: BigNumCompatible,
exponent: BigNumCompatible,
): BigNum;
/** Return a new BigNum with the instance value raised to the nth power modulo m. */
export function powm(
base: BigNumCompatible,
exponent: BigNumCompatible,
m: BigNumCompatible,
): BigNum;
/**
* If upperBound is supplied, return a random BigNum between the instance value and upperBound - 1, inclusive.
* Otherwise, return a random BigNum between 0 and the instance value - 1, inclusive.
*/
export function rand(
n: BigNumCompatible,
upperBound?: BigNumCompatible,
): BigNum;
/** Return the number of bits used to represent the current BigNum. */
export function bitLength(n: BigNumCompatible): number;
}
}
================================================
FILE: scripts/init.sh
================================================
#!/bin/bash
# Unofficial strict mode
set -euo pipefail
IFS=$'\n\t'
packageName=${1:-}
ROOT_PACKAGE_NAME=$(jq --raw-output '.name' package.json)
if [ "$ROOT_PACKAGE_NAME" != "lisk-elements-monorepo" ]; then
echo "Please use the command in the project root directory."
exit 1
fi
if [ -z "$packageName" ] || [[ "$packageName" =~ [^a-zA-Z0-9-] ]]; then
echo "Usage: npm run init -- PACKAGE_NAME"
exit 1
fi
packageDir="./packages/$packageName"
# Just in case package folder doesn't exist yet.
mkdir -p "$packageDir"
templates=(
"browsertest"
"cypress"
"scripts"
".babelrc"
".eslintignore"
".npmignore"
".npmrc"
".nycrc"
".prettierignore"
".prettierrc.json"
"cypress.json"
)
for i in "${templates[@]}"
do
if [ ! -e "$packageDir/${i}" ]; then
ln -vs "../../templates/$i.tmpl" "$packageDir/$i"
fi
done
================================================
FILE: templates/.npmignore.tmpl
================================================
.babelrc
.eslintignore
.eslintrc.json
.gitignore
.lintstagedrc.json
.nycrc
.prettierrc.json
cypress.json
index.html
Jenkinsfile*
.nyc_output/
coverage/
cypress/
fixtures/
src/
test/
browsertest/
================================================
FILE: templates/.npmrc.tmpl
================================================
message = ":arrow_up: Version %s"
save-exact = true
================================================
FILE: templates/.nycrc-ts.tmpl
================================================
{
"exclude": ["test/**", "**/*.d.ts"],
"extension": [".ts"]
}
================================================
FILE: templates/.prettierignore.tmpl
================================================
package.json
.nyc_output/
coverage/
dist-node/
dist-browser/
browsertest.build/
node_modules/
# BUG: See https://github.com/prettier/prettier/issues/3223
docs/CONTRIBUTING.md
================================================
FILE: templates/.prettierrc.json.tmpl
================================================
{
"singleQuote": true,
"trailingComma": "all",
"useTabs": true
}
================================================
FILE: templates/browsertest.tmpl/.eslintrc.json
================================================
{
"env": {
"mocha": true,
"browser": true
}
}
================================================
FILE: templates/browsertest.tmpl/browsertest.html
================================================
Browser tests
================================================
FILE: templates/browsertest.tmpl/browsertest.min.html
================================================
Browser tests
================================================
FILE: templates/browsertest.tmpl/run_tests.js
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
mocha.checkLeaks();
mocha.run(failures => {
document.getElementById('failures').innerText = failures;
document.getElementById('done').innerText = 'DONE';
});
================================================
FILE: templates/browsertest.tmpl/setup.js
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
mocha.setup({
ui: 'bdd',
timeout: 5000,
globals: ['__$$GLOBAL_REWIRE_NEXT_MODULE_ID__'],
fgrep: '@node-only',
invert: true,
});
================================================
FILE: templates/cypress.json.tmpl
================================================
{
"video": false,
"pluginsFile": false,
"supportFile": false
}
================================================
FILE: templates/cypress.tmpl/integration/index.js
================================================
/*
* Copyright © 2018 Lisk Foundation
*
* See the LICENSE file at the top-level directory of this distribution
* for licensing information.
*
* Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation,
* no part of this software, including this file, may be copied, modified,
* propagated, or distributed except according to the terms contained in the
* LICENSE file.
*
* Removal or modification of this copyright notice is prohibited.
*
*/
const ROOT_DIR = Cypress.env('ROOT_DIR');
const FORCE_RELOAD = true;
const throwFailuresInWindow = win => {
const failures = win.parent.document
.getElementById(`Your App: '${ROOT_DIR}'`)
.contentDocument.getElementsByClassName('fail');
if (failures.length) {
const failuresHTML = Array.from(failures).map(el => el.outerHTML);
let errorString;
try {
errorString = failuresHTML.map(decodeURIComponent).join('\n');
} catch (error) {
errorString = failuresHTML.join('\n');
}
throw new Error(errorString);
}
};
const testPage = page => () => {
cy.visit(page);
cy.reload(FORCE_RELOAD);
cy.get('#done').should('contain', 'DONE');
cy.window().then(throwFailuresInWindow);
};
describe('Browser tests', () => {
it('should pass without minification', testPage('/browsertest.html'));
it('should pass with minification', testPage('/browsertest.min.html'));
});
================================================
FILE: templates/mocha.opts.ts.tmpl
================================================
--recursive
--require ts-node/register
--require tsconfig-paths/register
--require source-map-support/register
--require ./test/_setup.ts
--watch-extensions ts
================================================
FILE: templates/scripts.tmpl/clean.sh
================================================
#!/bin/bash
# Unofficial strict mode
set -euo pipefail
IFS=$'\n\t'
# Usage
# npm run clean
rm -rf .nyc_output/
rm -rf browsertest.build/
rm -rf coverage/
rm -rf dist-browser/
rm -rf dist-node/
rm -rf lerna-debug.log
rm -rf npm-debug.log
================================================
FILE: templates/tsconfig-test.json.tmpl
================================================
{
"extends": "../tsconfig",
"compilerOptions": {
"baseUrl": ".",
"declaration": false,
"target": "es2017",
"typeRoots": ["../../../types", "../node_modules/@types"]
},
"include": ["../../../types/**/*", "./**/*"]
}
================================================
FILE: templates/tsconfig.browsertest.json.tmpl
================================================
{
"extends": "../../tsconfig",
"compilerOptions": {
"declaration": false,
"outDir": "browsertest.build",
"baseUrl": ".",
"rootDir": ".",
"typeRoots": [
"types",
"../../types",
"./node_modules/@types"
]
},
"include": ["../../types/**/*", "src/**/*", "test/**/*"]
}
================================================
FILE: templates/tsconfig.json.tmpl
================================================
{
"extends": "../../tsconfig",
"compilerOptions": {
"declaration": true,
"outDir": "dist-node",
"rootDir": "./src"
},
"include": ["src/**/*", "types/**/*"]
}
================================================
FILE: templates/tslint-test.json.tmpl
================================================
{
"extends": ["../../../tslint.test.json"]
}
================================================
FILE: templates/tslint.json.tmpl
================================================
{
"extends": "../../tslint.json"
}
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"target": "es2017",
"module": "commonjs",
"moduleResolution": "node",
"newLine": "lf",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"pretty": true,
"removeComments": true,
"resolveJsonModule": true,
"sourceMap": true,
"strict": true
}
}
================================================
FILE: tslint.json
================================================
{
"defaultSeverity": "error",
"extends": [
"tslint:all",
"tslint-immutable/all",
"tslint-config-prettier"
],
"rules": {
"completed-docs": false,
"file-name-casing": false,
"interface-name": [true, "never-prefix"],
"no-class": false,
"no-delete": true,
"no-expression-statement": false,
"no-if-statement": false,
"no-let": true,
"no-loop-statement": true,
"no-method-signature": false,
"no-mixed-interface": true,
"no-object-mutation": false,
"no-parameter-reassignment": true,
"no-this": false,
"no-unsafe-any": false,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"prefer-method-signature": false,
"readonly-array": true,
"readonly-keyword": [true, "ignore-class"],
"strict-boolean-expressions": false,
"strict-type-predicates": false
}
}
================================================
FILE: tslint.test.json
================================================
{
"rules": {
"arrow-return-shorthand": "off",
"no-expression-statement": "off"
}
}
================================================
FILE: types/chai/index.d.ts
================================================
/* tslint:disable:callable-types no-any no-method-signature readonly-keyword */
declare module 'chai' {
global {
export namespace Chai {
interface ChaiStatic {
_obj: any;
Assertion: {
new (value: any): Assertion;
addProperty(name: string, handler: () => void): void;
};
}
interface Assert {
(expression: any, message?: string, messageNegative?: string): void;
}
export interface TypeComparison {
hexString: Assertion;
integer: Assertion;
}
}
}
}
================================================
FILE: types/globals/index.d.ts
================================================
/* tslint:disable:readonly-keyword */
///
declare global {
export namespace NodeJS {
export interface Global {
sandbox: sinon.SinonSandbox;
}
}
var sandbox: sinon.SinonSandbox;
}
export {};
================================================
FILE: types/json/index.d.ts
================================================
/* tslint:disable:no-any */
declare module '*.json' {
const value: any;
export default value;
}