Compare commits

..

82 Commits

Author SHA1 Message Date
2537fa8920 improvement: updated folder structure 2021-10-08 12:29:17 -07:00
Louis Holbrook
6b59c87f68 Merge branch 'lash/okota' into 'master'
feat: Integrate okota

See merge request grassrootseconomics/cic-internal-integration!286
2021-10-07 21:05:58 +00:00
Louis Holbrook
9ee42b908d feat: Integrate okota 2021-10-07 21:05:58 +00:00
3343c4163e Merge branch 'lash/more-case-case' into 'master'
bug: cic-eth transaction listings

See merge request grassrootseconomics/cic-internal-integration!285
2021-10-07 15:12:35 +00:00
Louis Holbrook
f5bfc8ace2 bug: cic-eth transaction listings 2021-10-07 15:12:35 +00:00
8a9d2ee0be Merge branch 'bvander/default-docker-compose' into 'master'
chore: gift defaults

See merge request grassrootseconomics/cic-internal-integration!282
2021-09-27 13:15:21 +00:00
3608fd1fc7 chore: gift defaults 2021-09-27 16:14:31 +03:00
0d275f358b Merge branch 'philip/removes-docker-compose-profiles' into 'master'
removes profile attrs from docker-compose file.

See merge request grassrootseconomics/cic-internal-integration!281
2021-09-27 12:33:19 +00:00
3aef2aa65f removes profile attrs from docker-compose file. 2021-09-27 15:26:22 +03:00
5644baefb2 Merge branch 'philip/bump-cic-ussd-version' into 'master'
Bumps cic-ussd version following token fix.

See merge request grassrootseconomics/cic-internal-integration!280
2021-09-27 11:37:42 +00:00
1a7c4deab6 Bumps cic-ussd version following token fix. 2021-09-27 14:27:10 +03:00
0389d8623d Merge branch 'philip/token-value-fix' into 'master'
Refactors to avoid conversion of zero values to wei.

See merge request grassrootseconomics/cic-internal-integration!279
2021-09-22 08:17:39 +00:00
cf64387d81 Refactors to avoid conversion of zero values to wei. 2021-09-22 11:10:33 +03:00
79bcc8a9f1 Merge branch 'dev-k8s-deploy-new-data-seeding' into 'master'
Dataseeding container

See merge request grassrootseconomics/cic-internal-integration!267
2021-09-21 06:04:44 +00:00
7b57f1b4c2 Dataseeding container 2021-09-21 06:04:44 +00:00
76b8519637 Merge branch 'philip/cache-migration' into 'master'
Fixes migrations in cic-cache (ideally)

See merge request grassrootseconomics/cic-internal-integration!276
2021-09-21 05:33:46 +00:00
e89aec76fa Fixes migrations in cic-cache (ideally) 2021-09-21 05:33:46 +00:00
a138a0ec75 Merge branch 'bvander/update-buildkit-cache' into 'master'
chore: clean old dockerfile and add docs for clearing cache

See merge request grassrootseconomics/cic-internal-integration!277
2021-09-20 07:01:53 +00:00
5128c7828c chore: clean old dockerfile and add docs for clearing cache 2021-09-20 09:59:12 +03:00
2f005195e5 Merge branch 'philip/ussd-cli-fix' into 'master'
Philip/ussd cli fix

See merge request grassrootseconomics/cic-internal-integration!275
2021-09-18 09:07:05 +00:00
fb8db3ffd2 Philip/ussd cli fix 2021-09-18 09:07:05 +00:00
b5f647c4aa Merge branch 'philip/ussd-demurrage' into 'master'
Philip/ussd demurrage

See merge request grassrootseconomics/cic-internal-integration!263
2021-09-17 11:15:43 +00:00
6019143ba1 Philip/ussd demurrage 2021-09-17 11:15:43 +00:00
610440b722 Merge branch 'lash/signer-missing-symbol' into 'master'
Update signer to fill in missing sign to wire symbol

See merge request grassrootseconomics/cic-internal-integration!273
2021-09-17 06:54:58 +00:00
Louis Holbrook
d65455fc29 Update signer to fill in missing sign to wire symbol 2021-09-17 06:54:58 +00:00
43f8d1c30c Merge branch 'bvander/docker-compose-restarts' into 'master'
chore: fix docker compose restarts

See merge request grassrootseconomics/cic-internal-integration!274
2021-09-16 11:17:42 +00:00
b855211eed chore: fix docker compose restarts 2021-09-16 13:06:53 +03:00
1e0c475f39 Merge branch 'lash/contract-migration-dump' into 'master'
fix(contract-migration): Replace missing environment

See merge request grassrootseconomics/cic-internal-integration!271
2021-09-15 13:36:10 +00:00
Louis Holbrook
3e6cf594e3 fix(contract-migration): Replace missing environment 2021-09-15 13:36:09 +00:00
b8f79a2dd1 Merge branch 'bvander/extend-timoeout-contract-migration' into 'master'
chore: extend timeout for contract migration

See merge request grassrootseconomics/cic-internal-integration!272
2021-09-15 11:08:14 +00:00
540c2fd950 chore: extend timeout for contract migration 2021-09-15 14:04:18 +03:00
b9b06eced8 Merge branch 'staging' into 'master'
feat: add multi-project build to trigger deploy-k8s-dev in the devops repo

See merge request grassrootseconomics/cic-internal-integration!268
2021-09-09 21:28:49 +00:00
949bb29379 feat: add multi-project build to trigger deploy-k8s-dev in the devops repo 2021-09-09 21:28:49 +00:00
Louis Holbrook
0468906601 Merge branch 'lash/contract-migration-dump' into 'master'
fix(contract-migration): Make http signer work with local deployment

See merge request grassrootseconomics/cic-internal-integration!270
2021-09-09 13:38:10 +00:00
nolash
471243488e Add latest crypto-dev-signer install explicitly in dockerfile for cic-eth 2021-09-09 14:27:47 +02:00
3c4acd82ff test eth and meta only mrs 2021-09-07 11:56:17 -07:00
e07f992c5a Add new file 2021-09-07 18:38:20 +00:00
17e95cb19c Merge branch 'bvander/signer-as-service' into 'master'
run signer as a service over http

See merge request grassrootseconomics/cic-internal-integration!265
2021-09-06 19:10:08 +00:00
3c3a97ce15 run signer as a service over http 2021-09-06 12:07:57 -07:00
a492be4927 Merge branch 'lash/contract-migration-config' into 'master'
Sanitize contract migration configs

See merge request grassrootseconomics/cic-internal-integration!262
2021-09-06 10:06:58 +00:00
Louis Holbrook
1f555748b0 Sanitize contract migration configs 2021-09-06 10:06:58 +00:00
8aa4d20eea Update .gitlab-ci.yml 2021-09-01 20:00:44 +00:00
Louis Holbrook
90cf24dcee Merge branch 'lash/lockfix' into 'master'
Rehabilitate imports

See merge request grassrootseconomics/cic-internal-integration!261
2021-09-01 16:54:10 +00:00
Louis Holbrook
75b711dbd5 Rehabilitate imports 2021-09-01 16:54:10 +00:00
c21c1eb2ef fix data seeding node installs 2021-08-31 11:43:01 -07:00
eb5e612105 minor update to import_ussd script 2021-08-30 11:09:47 -07:00
e017d11770 update readme 2021-08-30 10:14:22 -07:00
e327af68e1 Merge branch 'philip/refactor-import-scripts' into 'master'
Consolidated ussd dataseeding script

See merge request grassrootseconomics/cic-internal-integration!252
2021-08-29 09:55:47 +00:00
92cc6a3f27 Consolidated ussd dataseeding script 2021-08-29 09:55:47 +00:00
f42bf7754a Merge branch 'lash/lockfix' into 'master'
Normalize initial INIT lock address

See merge request grassrootseconomics/cic-internal-integration!260
2021-08-29 09:07:46 +00:00
nolash
7342927e91 Normalize initial INIT lock address 2021-08-29 10:43:12 +02:00
17333af88f Merge branch 'bvander/docker-vm-builds' into 'master'
docker vm builds

See merge request grassrootseconomics/cic-internal-integration!259
2021-08-28 16:26:16 +00:00
6a68d2ed32 docker vm builds 2021-08-28 16:26:16 +00:00
Louis Holbrook
ef77f4c99a Merge branch 'lash/normalize-backend-tx' into 'master'
Normalize tx data for backend

Closes cic-eth#133

See merge request grassrootseconomics/cic-internal-integration!258
2021-08-28 11:10:18 +00:00
Louis Holbrook
56dbe8a502 Normalize tx data for backend 2021-08-28 11:10:18 +00:00
Louis Holbrook
2dc8ac6a12 Merge branch 'lash/upgrade-outer-tools' into 'master'
Upgrade outer tools

See merge request grassrootseconomics/cic-internal-integration!257
2021-08-27 13:13:00 +00:00
Louis Holbrook
0ced68e224 Upgrade outer tools 2021-08-27 13:13:00 +00:00
2afb20e715 Merge branch 'philip/ussd-post-test-bug-fixes' into 'master'
USSD post-test bug fixes

See merge request grassrootseconomics/cic-internal-integration!244
2021-08-25 10:33:35 +00:00
3b0113d0e4 USSD post-test bug fixes 2021-08-25 10:33:35 +00:00
Louis Holbrook
ebf4743a84 Merge branch 'lash/traffic-script-rehab' into 'master'
Implement chainlib cli for traffic script

See merge request grassrootseconomics/cic-internal-integration!255
2021-08-25 09:33:23 +00:00
Louis Holbrook
3bf92e7a8a Implement chainlib cli for traffic script 2021-08-25 09:33:23 +00:00
f0b4c42c68 cleanup contract migration dockerfiles 2021-08-24 15:33:18 -07:00
Louis Holbrook
b62d00180c Merge branch 'lash/cic-eth-seeding-fix' into 'master'
cic-eth data seeding rehab

See merge request grassrootseconomics/cic-internal-integration!254
2021-08-24 21:07:36 +00:00
Louis Holbrook
a49978cc36 cic-eth data seeding rehab 2021-08-24 21:07:36 +00:00
1b0ee269d0 add pre tag to contract-migration 2021-08-24 11:43:39 -07:00
aa2f363b27 fix em 2021-08-24 10:42:30 -07:00
2a24ce6938 remove mount 2021-08-24 10:33:53 -07:00
938a10b5c3 contract-migration ci parity 2021-08-24 10:26:09 -07:00
Louis Holbrook
76e33e578b Merge branch 'lash/verify-details' into 'master'
Add target count to verify

Closes #103

See merge request grassrootseconomics/cic-internal-integration!246
2021-08-24 15:56:41 +00:00
Louis Holbrook
2ec4262734 Add target count to verify 2021-08-24 15:56:41 +00:00
Louis Holbrook
7684fe3883 Merge branch 'lash/cic-eth-upgrade-more' into 'master'
Upgrade cic-ussd deps

See merge request grassrootseconomics/cic-internal-integration!247
2021-08-24 15:25:11 +00:00
Louis Holbrook
995a148c6a Upgrade cic-ussd deps 2021-08-24 15:25:11 +00:00
Louis Holbrook
511e099689 Merge branch 'lash/signer-update' into 'master'
Update signer

See merge request grassrootseconomics/cic-internal-integration!253
2021-08-24 11:35:52 +00:00
Louis Holbrook
f877218c55 Update signer 2021-08-24 11:35:52 +00:00
8ac9a1e99a reverting to fffb2bc3f4 2021-08-21 13:23:43 -04:00
c4cb095a29 Merge branch 'bvander/fix-cic-staff-client-docker' into 'master'
fix issues with build cicada, now it should do auto reload

See merge request grassrootseconomics/cic-internal-integration!250
2021-08-19 20:15:22 +00:00
05b8bbbbca fix issues with build cicada, now it should do auto reload 2021-08-19 20:15:22 +00:00
1ce32fbbe0 Merge branch 'fix-meta-docker-compose' into 'master'
fix a bug in the meta tag

See merge request grassrootseconomics/cic-internal-integration!249
2021-08-19 16:48:43 +00:00
3fd5e77e2c fix a bug in the meta tag 2021-08-19 12:46:32 -04:00
e27a49ef33 add docker swarm deployment configs and remove dependency on kaniko for ci builds 2021-08-19 12:29:41 -04:00
Louis Holbrook
fffb2bc3f4 Merge branch 'lash/faucet-workaround' into 'master'
Empty config dir in faucet setup

See merge request grassrootseconomics/cic-internal-integration!240
2021-08-18 06:34:08 +00:00
Louis Holbrook
8910fb0759 Empty config dir in faucet setup 2021-08-18 06:34:07 +00:00
1490 changed files with 190061 additions and 211664 deletions

40
.env
View File

@@ -1,40 +0,0 @@
DOMAIN=localhost
STACK_NAME=cic-net
TRAEFIK_PUBLIC_NETWORK=traefik-public
TRAEFIK_TAG=cic.net
TRAEFIK_PUBLIC_TAG=traefik-public
TAG=localhost
FRONTEND_ENV=dev
# Flower
FLOWER_BASIC_AUTH=admin:changethis
# Postgres
DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE_ENGINE=postgresql
DATABASE_DRIVER=psycopg2
DATABASE_USER=postgres
DATABASE_NAME=cic_eth
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_DB=0
# Celery Broker
CELERY_BROKER_URL=redis://redis:6379
CELERY_RESULT_URL=redis://redis:6379
# Blockchain node
ETH_PROVIDER=http://eth:8545
CIC_CHAIN_SPEC=evm:bloxberg:8996
# PgAdmin
PGADMIN_LISTEN_PORT=5050
PGADMIN_DEFAULT_EMAIL=admin@cic.net
PGADMIN_DEFAULT_PASSWORD=changethis

3
.gitignore vendored
View File

@@ -14,4 +14,5 @@ build/
**/.venv
.idea
**/.vim
docker-stack.yml
**/*secret.yaml
.env

View File

@@ -1,99 +1,43 @@
include:
# - local: 'ci_templates/.cic-template.yml'
# - local: 'apps/contract-migration/.gitlab-ci.yml'
#- local: 'ci_templates/.cic-template.yml' #kaniko build templates
# these includes are app specific unit tests
- local: 'apps/cic-eth/.gitlab-ci.yml'
- local: 'apps/cic-ussd/.gitlab-ci.yml'
- local: 'apps/cic-notify/.gitlab-ci.yml'
- local: 'apps/cic-meta/.gitlab-ci.yml'
- local: 'apps/cic-cache/.gitlab-ci.yml'
# - local: 'apps/data-seeding/.gitlab-ci.yml'
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/docker-with-compose:latest
#- local: 'apps/contract-migration/.gitlab-ci.yml'
#- local: 'apps/data-seeding/.gitlab-ci.yml'
stages:
- build
- test
- deploy
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/docker-with-compose:latest
variables:
DOCKER_BUILDKIT: "1"
COMPOSE_DOCKER_CLI_BUILD: "1"
MR_IMAGE_TAG: mr-$CI_COMMIT_SHORT_SHA
COMPOSE_DOCKER_CLI_BUILD: "1"
CI_DEBUG_TRACE: "true"
# todo you can probably just build the single image w/o docker-compose
build-merge-request:
before_script:
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
# runs on protected branches and pushes to repo
build-push:
stage: build
tags:
- integration
variables:
CI_DEBUG_TRACE: "true"
#script:
# - TAG=$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA sh ./scripts/build-push.sh
script:
- TAG=$MR_IMAGE_TAG FRONTEND_ENV=dev sh ./scripts/build-push.sh
- TAG=latest sh ./scripts/build-push.sh
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_REF_PROTECTED == "true"
when: always
build-staging:
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
tags:
- integration
#- blocal
variables:
CI_DEBUG_TRACE: "true"
stage: build
script:
- TAG=stag FRONTEND_ENV=staging sh ./scripts/build-push.sh
only:
- staging
deploy-staging:
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- pip install docker-auto-labels
tags:
- integration
deploy-dev:
stage: deploy
script:
- >
DOMAIN=stag.grassrootseconomics.net
TRAEFIK_TAG=grassrootseconomics.net
STACK_NAME=stag-cic-net
TAG=stag
sh ./scripts/deploy.sh
environment:
name: staging
url: https://stag.grassrootseconomics.net
only:
- staging
#build-prod:
# stage: build
# script:
# - TAG=prod FRONTEND_ENV=production sh ./scripts/build-push.sh
# only:
# - production
# tags:
# - build
# - test
#
#deploy-prod:
# stage: deploy
# script:
# - >
# DOMAIN=demo1.com
# TRAEFIK_TAG=demo1.com
# STACK_NAME=demo1-com
# TAG=prod
# sh ./scripts/deploy.sh
# environment:
# name: production
# url: https://demo1.com
# only:
# - production
# tags:
# - swarm
# - prod
trigger: grassrootseconomics/devops
when: manual

106
README.md
View File

@@ -1,104 +1,44 @@
# cic-internal-integration
## Backend Requirements
## Getting started
* [Docker](https://www.docker.com/).
* [Docker Compose](https://docs.docker.com/compose/install/).
### Preperation
## Backend local development
Copy the .env_sample file to .env and populate with appropriate env vars
* Start the stack with Docker Compose:
This repo uses docker-compose and docker buildkit. Set the following environment variables to get started:
```bash
```
export COMPOSE_DOCKER_CLI_BUILD=1
export DOCKER_BUILDKIT=1
```
start services, database, redis and local ethereum node
```
docker-compose up -d
```
* Now you can open your browser and interact with these URLs:
Frontend (CICADA), built with Docker, with routes handled based on the path: http://localhost
PGAdmin, PostgreSQL web administration: http://localhost:5050
Flower, administration of Celery tasks: http://localhost:5555
Traefik UI, to see how the routes are being handled by the proxy: http://localhost:8090
**Note**: The first time you start your stack, it might take a minute for it to be ready. While the backend waits for the database to be ready and configures everything. You can check the logs to monitor it.
To check the logs, run:
```bash
docker-compose logs
Run app/contract-migration to deploy contracts
```
RUN_MASK=3 docker-compose up contract-migration
```
To check the logs of a specific service, add the name of the service, e.g.:
```bash
docker-compose logs backend
stop cluster
```
docker-compose down
```
If your Docker is not running in `localhost` (the URLs above wouldn't work) check the sections below on **Development with Docker Toolbox** and **Development with a custom IP**.
#### Deploy the stack locally
If you want to run the docker stack locally on swarm
stop cluster and delete data
```
docker-compose -f docker-compose.yml -f docker-compose.override.yml config > docker-stack.yml
docker-compose down -v --remove-orphans
```
rebuild an images
```
docker node update z1ehkrw1mvqlxc2udwt4xpype --label-add cic-net.app-db-data=true
docker stack deploy -c docker-stack.yml cic-net
docker-compose up --build <service_name>
```
## Backend local development, additional details
**fill me in**
### Docker Compose Override
During development, you can change Docker Compose settings that will only affect the local development environment, in the file `docker-compose.override.yml`.
The changes to that file only affect the local development environment, not the production environment. So, you can add "temporary" changes that help the development workflow.
For example, the directory with the backend code is mounted as a Docker "host volume", mapping the code you change live to the directory inside the container. That allows you to test your changes right away, without having to build the Docker image again. It should only be done during development, for production, you should build the Docker image with a recent version of the backend code. But during development, it allows you to iterate very fast.
There is also a command override that runs `/start-reload.sh` (included in the base image) instead of the default `/start.sh` (also included in the base image). It starts a single server process (instead of multiple, as would be for production) and reloads the process whenever the code changes. Have in mind that if you have a syntax error and save the Python file, it will break and exit, and the container will stop. After that, you can restart the container by fixing the error and running again:
```console
$ docker-compose up -d
to delete the buildkit cache
```
There is also a commented out `command` override, you can uncomment it and comment the default one. It makes the backend container run a process that does "nothing", but keeps the container alive. That allows you to get inside your running container and execute commands inside, for example a Python interpreter to test installed dependencies, or start the development server that reloads when it detects changes, or start a Jupyter Notebook session.
To get inside the container with a `bash` session you can start the stack with:
```console
$ docker-compose up -d
docker builder prune --filter type=exec.cachemount
```
and then `exec` inside the running container:
```console
$ docker-compose exec backend bash
```
You should see an output like:
```console
root@7f2607af31c3:/app#
```
#### Test running stack
If your stack is already up and you just want to run the tests, you can use:
```bash
docker-compose exec data-seeding /script/run_ussd_user_imports.sh
```

View File

@@ -1,5 +1,4 @@
.git
.cache
.dot
**/doc
**/node_modules/
**/doc

View File

@@ -1,41 +1,17 @@
.cic_cache_variables:
variables:
APP_NAME: cic-cache
#build-mr-cic-cache:
# extends:
# - .py_build_merge_request
# - .cic_cache_variables
# rules:
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# changes:
# - apps/cic-cache/**/*
# when: always
test-mr-cic-cache:
stage: test
tags:
- integration
extends:
- .cic_cache_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/$APP_NAME:$MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_cache --cov-fail-under=90 --cov-report term-missing tests
allow_failure: true
needs: ["build-merge-request"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always
build-test-cic-cache:
stage: test
tags:
- integration
variables:
APP_NAME: cic-cache
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
script:
- cd apps/cic-cache
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile .
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always

View File

@@ -0,0 +1 @@
# CIC-CACHE

View File

@@ -27,11 +27,11 @@ class RPC:
@staticmethod
def from_config(config):
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
RPCConnection.register_location(config.get('RPC_HTTP_PROVIDER'), chain_spec, 'default')
RPCConnection.register_location(config.get('RPC_PROVIDER'), chain_spec, 'default')
if config.get('SIGNER_PROVIDER'):
RPCConnection.register_constructor(ConnType.UNIX, EthUnixSignerConnection, tag='signer')
RPCConnection.register_location(config.get('SIGNER_PROVIDER'), chain_spec, 'signer')
rpc = RPC(chain_spec, config.get('RPC_HTTP_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER'))
rpc = RPC(chain_spec, config.get('RPC_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER'))
logg.info('set up rpc: {}'.format(rpc))
return rpc

View File

@@ -5,7 +5,7 @@ version = (
0,
2,
1,
'alpha.1',
'alpha.2',
)
version_object = semver.VersionInfo(

View File

@@ -10,9 +10,10 @@ COPY requirements.txt .
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG EXTRA_PIP_ARGS=""
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
--extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL $EXTRA_PIP_ARGS \
-r requirements.txt
COPY . .

View File

@@ -0,0 +1,10 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_cache --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -2,16 +2,13 @@ alembic==1.4.2
confini>=0.3.6rc4,<0.5.0
uwsgi==2.0.19.1
moolb~=0.1.1b2
cic-eth-registry~=0.5.8a1
cic-eth-registry~=0.6.1a1
SQLAlchemy==1.3.20
semver==2.13.0
psycopg2==2.8.6
celery==4.4.7
redis==3.5.3
chainsyncer[sql]>=0.0.6a1,<0.1.0
erc20-faucet>=0.2.4a2, <0.3.0
#chainlib-eth==0.0.7a5,<0.1.0
chainlib-eth==0.0.7a5
#chainlib==0.0.7a4,<0.1.0
chainlib==0.0.7a4
eth-address-index>=0.1.4a1,<0.2.0
chainsyncer[sql]>=0.0.6a3,<0.1.0
erc20-faucet>=0.3.2a2, <0.4.0
chainlib-eth>=0.0.9a14,<0.1.0
eth-address-index>=0.2.3a4,<0.3.0

View File

@@ -6,5 +6,5 @@ sqlparse==0.4.1
pytest-celery==0.0.0a1
eth_tester==0.5.0b3
py-evm==0.3.0a20
sarafu-faucet~=0.0.5a2
erc20-transfer-authorization>=0.3.4a1,<0.4.0
sarafu-faucet~=0.0.7a1
erc20-transfer-authorization>=0.3.5a1,<0.4.0

View File

@@ -1,5 +1,4 @@
celery==4.4.7
erc20-demurrage-token~=0.0.3a1
cic-eth-registry~=0.5.8a1
chainlib~=0.0.7a1
cic_eth~=0.12.2a4
cic-eth-registry>=0.6.1a2,<0.7.0
cic-eth[services]~=0.12.4a8

View File

@@ -1,53 +1,16 @@
.cic_eth_variables:
variables:
APP_NAME: cic-eth
#build-mr-cic-eth:
# extends:
# - .cic_eth_variables
# - .py_build_target_dev
# rules:
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# changes:
# - apps/cic-eth/**/*
# when: always
test-mr-cic-eth:
stage: test
tags:
- integration
extends:
- .cic_eth_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/$APP_NAME:$MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r admin_requirements.txt
-r services_requirements.txt
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests
allow_failure: true
needs: ["build-merge-request"]
rules:
build-test-cic-eth:
stage: test
tags:
- integration
variables:
APP_NAME: cic-eth
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
script:
- cd apps/cic-eth
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile .
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always
#build-push-cic-eth:
# extends:
# - .py_build_push
# - .cic_eth_variables
# rules:
# - if: $CI_COMMIT_BRANCH == "master"
# changes:
# - apps/cic-eth/**/*
# when: always

View File

@@ -1,5 +1,5 @@
SQLAlchemy==1.3.20
cic-eth-registry>=0.5.6a2,<0.6.0
hexathon~=0.0.1a7
chainqueue>=0.0.3a1,<0.1.0
eth-erc20>=0.0.10a3,<0.1.0
cic-eth-registry>=0.6.1a3,<0.7.0
hexathon~=0.0.1a8
chainqueue>=0.0.4a6,<0.1.0
eth-erc20>=0.1.2a2,<0.2.0

View File

@@ -4,7 +4,6 @@ import logging
# external imports
import celery
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.chain import ChainSpec
from hexathon import (
add_0x,
@@ -20,18 +19,17 @@ from cic_eth.task import (
CriticalSQLAlchemyTask,
)
from cic_eth.error import LockedError
from cic_eth.encode import (
tx_normalize,
ZERO_ADDRESS_NORMAL,
)
celery_app = celery.current_app
logg = logging.getLogger()
def normalize_address(a):
if a == None:
return None
return add_0x(hex_uniform(strip_0x(a)))
@celery_app.task(base=CriticalSQLAlchemyTask)
def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.ALL, tx_hash=None):
def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=LockEnum.ALL, tx_hash=None):
"""Task wrapper to set arbitrary locks
:param chain_str: Chain spec string representation
@@ -43,7 +41,7 @@ def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.AL
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = '::'
if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
@@ -53,7 +51,7 @@ def lock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.AL
@celery_app.task(base=CriticalSQLAlchemyTask)
def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.ALL):
def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, flags=LockEnum.ALL):
"""Task wrapper to reset arbitrary locks
:param chain_str: Chain spec string representation
@@ -65,7 +63,7 @@ def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = '::'
if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
@@ -75,7 +73,7 @@ def unlock(chained_input, chain_spec_dict, address=ZERO_ADDRESS, flags=LockEnum.
@celery_app.task(base=CriticalSQLAlchemyTask)
def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None):
def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_hash=None):
"""Task wrapper to set send lock
:param chain_str: Chain spec string representation
@@ -85,7 +83,7 @@ def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.set(chain_str, LockEnum.SEND, address=address, tx_hash=tx_hash)
logg.debug('Send locked for {}, flag now {}'.format(address, r))
@@ -93,7 +91,7 @@ def lock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None
@celery_app.task(base=CriticalSQLAlchemyTask)
def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL):
"""Task wrapper to reset send lock
:param chain_str: Chain spec string representation
@@ -103,7 +101,7 @@ def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.reset(chain_str, LockEnum.SEND, address=address)
logg.debug('Send unlocked for {}, flag now {}'.format(address, r))
@@ -111,7 +109,7 @@ def unlock_send(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
@celery_app.task(base=CriticalSQLAlchemyTask)
def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=None):
def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL, tx_hash=None):
"""Task wrapper to set queue direct lock
:param chain_str: Chain spec string representation
@@ -121,7 +119,7 @@ def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=Non
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash)
logg.debug('Queue direct locked for {}, flag now {}'.format(address, r))
@@ -129,7 +127,7 @@ def lock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS, tx_hash=Non
@celery_app.task(base=CriticalSQLAlchemyTask)
def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS_NORMAL):
"""Task wrapper to reset queue direct lock
:param chain_str: Chain spec string representation
@@ -139,7 +137,7 @@ def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
:returns: New lock state for address
:rtype: number
"""
address = normalize_address(address)
address = tx_normalize.wallet_address(address)
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
r = Lock.reset(chain_str, LockEnum.QUEUE, address=address)
logg.debug('Queue direct unlocked for {}, flag now {}'.format(address, r))
@@ -148,12 +146,13 @@ def unlock_queue(chained_input, chain_spec_dict, address=ZERO_ADDRESS):
@celery_app.task(base=CriticalSQLAlchemyTask)
def check_lock(chained_input, chain_spec_dict, lock_flags, address=None):
address = normalize_address(address)
if address != None:
address = tx_normalize.wallet_address(address)
chain_str = '::'
if chain_spec_dict != None:
chain_str = str(ChainSpec.from_dict(chain_spec_dict))
session = SessionBase.create_session()
r = Lock.check(chain_str, lock_flags, address=ZERO_ADDRESS, session=session)
r = Lock.check(chain_str, lock_flags, address=ZERO_ADDRESS_NORMAL, session=session)
if address != None:
r |= Lock.check(chain_str, lock_flags, address=address, session=session)
if r > 0:

View File

@@ -33,6 +33,7 @@ from cic_eth.admin.ctrl import (
from cic_eth.queue.tx import queue_create
from cic_eth.eth.gas import create_check_gas_task
from cic_eth.task import BaseTask
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
logg = logging.getLogger()
@@ -73,7 +74,7 @@ def shift_nonce(self, chainspec_dict, tx_hash_orig_hex, delta=1):
set_cancel(chain_spec, strip_0x(tx['hash']), manual=True, session=session)
query_address = add_0x(hex_uniform(strip_0x(address))) # aaaaargh
query_address = tx_normalize.wallet_address(address)
q = session.query(Otx)
q = q.join(TxCache)
q = q.filter(TxCache.sender==query_address)

View File

@@ -32,7 +32,6 @@ from chainqueue.db.enum import (
status_str,
)
from chainqueue.error import TxStateChangeError
from chainqueue.sql.query import get_tx
from eth_erc20 import ERC20
# local imports
@@ -40,6 +39,7 @@ from cic_eth.db.models.base import SessionBase
from cic_eth.db.models.role import AccountRole
from cic_eth.db.models.nonce import Nonce
from cic_eth.error import InitializationError
from cic_eth.queue.query import get_tx_local
app = celery.current_app
@@ -284,7 +284,7 @@ class AdminApi:
tx_hash_hex = None
session = SessionBase.create_session()
for k in txs.keys():
tx_dict = get_tx(chain_spec, k, session=session)
tx_dict = get_tx_local(chain_spec, k, session=session)
if tx_dict['nonce'] == nonce:
tx_hash_hex = k
session.close()

View File

@@ -9,6 +9,7 @@ import logging
# external imports
import celery
from chainlib.chain import ChainSpec
from hexathon import strip_0x
# local imports
from cic_eth.api.base import ApiBase
@@ -254,6 +255,8 @@ class Api(ApiBase):
:returns: uuid of root task
:rtype: celery.Task
"""
#from_address = strip_0x(from_address)
#to_address = strip_0x(to_address)
s_check = celery.signature(
'cic_eth.admin.ctrl.check_lock',
[

View File

@@ -35,14 +35,14 @@ class RPC:
def from_config(config, use_signer=False, default_label='default', signer_label='signer'):
chain_spec = ChainSpec.from_chain_str(config.get('CHAIN_SPEC'))
RPCConnection.register_location(config.get('RPC_HTTP_PROVIDER'), chain_spec, default_label)
RPCConnection.register_location(config.get('RPC_PROVIDER'), chain_spec, default_label)
if use_signer:
RPCConnection.register_constructor(ConnType.UNIX, EthUnixSignerConnection, signer_label)
RPCConnection.register_constructor(ConnType.HTTP, EthHTTPSignerConnection, signer_label)
RPCConnection.register_constructor(ConnType.HTTP_SSL, EthHTTPSignerConnection, signer_label)
RPCConnection.register_location(config.get('SIGNER_PROVIDER'), chain_spec, signer_label)
rpc = RPC(chain_spec, config.get('RPC_HTTP_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER'))
rpc = RPC(chain_spec, config.get('RPC_PROVIDER'), signer_provider=config.get('SIGNER_PROVIDER'))
logg.info('set up rpc: {}'.format(rpc))
return rpc

View File

@@ -8,8 +8,8 @@ Create Date: 2021-04-02 18:41:20.864265
import datetime
from alembic import op
import sqlalchemy as sa
from chainlib.eth.constant import ZERO_ADDRESS
from cic_eth.db.enum import LockEnum
from cic_eth.encode import ZERO_ADDRESS_NORMAL
# revision identifiers, used by Alembic.
@@ -30,7 +30,7 @@ def upgrade():
sa.Column("otx_id", sa.Integer, sa.ForeignKey('otx.id'), nullable=True),
)
op.create_index('idx_chain_address', 'lock', ['blockchain', 'address'], unique=True)
op.execute("INSERT INTO lock (address, date_created, blockchain, flags) VALUES('{}', '{}', '::', {})".format(ZERO_ADDRESS, datetime.datetime.utcnow(), LockEnum.INIT | LockEnum.SEND | LockEnum.QUEUE))
op.execute("INSERT INTO lock (address, date_created, blockchain, flags) VALUES('{}', '{}', '::', {})".format(ZERO_ADDRESS_NORMAL, datetime.datetime.utcnow(), LockEnum.INIT | LockEnum.SEND | LockEnum.QUEUE))
def downgrade():

View File

@@ -4,12 +4,12 @@ import logging
# third-party imports
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey
from chainlib.eth.constant import ZERO_ADDRESS
from chainqueue.db.models.tx import TxCache
from chainqueue.db.models.otx import Otx
# local imports
from cic_eth.db.models.base import SessionBase
from cic_eth.encode import ZERO_ADDRESS_NORMAL
logg = logging.getLogger()
@@ -37,7 +37,7 @@ class Lock(SessionBase):
@staticmethod
def set(chain_str, flags, address=ZERO_ADDRESS, session=None, tx_hash=None):
def set(chain_str, flags, address=ZERO_ADDRESS_NORMAL, session=None, tx_hash=None):
"""Sets flags associated with the given address and chain.
If a flags entry does not exist it is created.
@@ -90,7 +90,7 @@ class Lock(SessionBase):
@staticmethod
def reset(chain_str, flags, address=ZERO_ADDRESS, session=None):
def reset(chain_str, flags, address=ZERO_ADDRESS_NORMAL, session=None):
"""Resets flags associated with the given address and chain.
If the resulting flags entry value is 0, the entry will be deleted.
@@ -134,7 +134,7 @@ class Lock(SessionBase):
@staticmethod
def check(chain_str, flags, address=ZERO_ADDRESS, session=None):
def check(chain_str, flags, address=ZERO_ADDRESS_NORMAL, session=None):
"""Checks whether all given flags are set for given address and chain.
Does not validate the address against any other tables or components.

View File

@@ -0,0 +1,16 @@
# external imports
from chainlib.eth.constant import ZERO_ADDRESS
from chainqueue.encode import TxHexNormalizer
from chainlib.eth.tx import unpack
tx_normalize = TxHexNormalizer()
ZERO_ADDRESS_NORMAL = tx_normalize.wallet_address(ZERO_ADDRESS)
def unpack_normal(signed_tx_bytes, chain_spec):
tx = unpack(signed_tx_bytes, chain_spec)
tx['hash'] = tx_normalize.tx_hash(tx['hash'])
tx['from'] = tx_normalize.wallet_address(tx['from'])
tx['to'] = tx_normalize.wallet_address(tx['to'])
return tx

View File

@@ -13,11 +13,8 @@ from chainlib.eth.sign import (
new_account,
sign_message,
)
from chainlib.eth.address import to_checksum_address
from chainlib.eth.tx import (
TxFormat,
unpack,
)
from chainlib.eth.address import to_checksum_address, is_address
from chainlib.eth.tx import TxFormat
from chainlib.chain import ChainSpec
from chainlib.error import JSONRPCException
from eth_accounts_index.registry import AccountRegistry
@@ -34,6 +31,7 @@ from cic_eth.eth.gas import (
from cic_eth.db.models.nonce import Nonce
from cic_eth.db.models.base import SessionBase
from cic_eth.db.models.role import AccountRole
from cic_eth.encode import tx_normalize
from cic_eth.error import (
RoleMissingError,
SignerError,
@@ -49,6 +47,11 @@ from cic_eth.eth.nonce import (
from cic_eth.queue.tx import (
register_tx,
)
from cic_eth.encode import (
unpack_normal,
ZERO_ADDRESS_NORMAL,
tx_normalize,
)
logg = logging.getLogger()
celery_app = celery.current_app
@@ -83,7 +86,7 @@ def create(self, password, chain_spec_dict):
# TODO: It seems infeasible that a can be None in any case, verify
if a == None:
raise SignerError('create account')
a = tx_normalize.wallet_address(a)
logg.debug('created account {}'.format(a))
# Initialize nonce provider record for account
@@ -174,6 +177,9 @@ def gift(self, account_address, chain_spec_dict):
"""
chain_spec = ChainSpec.from_dict(chain_spec_dict)
if is_address(account_address):
account_address = tx_normalize.wallet_address(account_address)
logg.debug('gift account address {} to index'.format(account_address))
queue = self.request.delivery_info.get('routing_key')
@@ -247,8 +253,9 @@ def have(self, account, chain_spec_dict):
@celery_app.task(bind=True, base=CriticalSQLAlchemyTask)
def set_role(self, tag, address, chain_spec_dict):
if not to_checksum_address(address):
raise ValueError('invalid checksum address {}'.format(address))
if not is_address(address):
raise ValueError('invalid address {}'.format(address))
address = tx_normalize.wallet_address(address)
session = SessionBase.create_session()
role = AccountRole.set(tag, address, session=session)
session.add(role)
@@ -295,17 +302,19 @@ def cache_gift_data(
chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx = unpack_normal(tx_signed_raw_bytes, chain_spec)
tx_data = Faucet.parse_give_to_request(tx['data'])
sender_address = tx_normalize.wallet_address(tx['from'])
recipient_address = tx_normalize.wallet_address(tx['to'])
session = self.create_session()
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': tx['to'],
'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS,
'hash': tx['hash'],
'from': sender_address,
'to': recipient_address,
'source_token': ZERO_ADDRESS_NORMAL,
'destination_token': ZERO_ADDRESS_NORMAL,
'from_value': 0,
'to_value': 0,
}
@@ -334,17 +343,19 @@ def cache_account_data(
:rtype: tuple
"""
chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(tx_signed_raw_hex[2:])
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack_normal(tx_signed_raw_bytes, chain_spec)
tx_data = AccountsIndex.parse_add_request(tx['data'])
sender_address = tx_normalize.wallet_address(tx['from'])
recipient_address = tx_normalize.wallet_address(tx['to'])
session = SessionBase.create_session()
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'to': tx['to'],
'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS,
'hash': tx['hash'],
'from': sender_address,
'to': recipient_address,
'source_token': ZERO_ADDRESS_NORMAL,
'destination_token': ZERO_ADDRESS_NORMAL,
'from_value': 0,
'to_value': 0,
}

View File

@@ -12,7 +12,10 @@ from chainlib.eth.tx import (
)
from cic_eth_registry import CICRegistry
from cic_eth_registry.erc20 import ERC20Token
from hexathon import strip_0x
from hexathon import (
strip_0x,
add_0x,
)
from chainqueue.error import NotLocalTxError
from eth_erc20 import ERC20
from chainqueue.sql.tx import cache_tx_dict
@@ -38,6 +41,7 @@ from cic_eth.task import (
CriticalSQLAlchemyAndSignerTask,
)
from cic_eth.eth.nonce import CustodialTaskNonceOracle
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
logg = logging.getLogger()
@@ -62,7 +66,8 @@ def balance(tokens, holder_address, chain_spec_dict):
for t in tokens:
address = t['address']
token = ERC20Token(chain_spec, rpc, address)
logg.debug('address {} {}'.format(address, holder_address))
token = ERC20Token(chain_spec, rpc, add_0x(address))
c = ERC20(chain_spec)
o = c.balance_of(address, holder_address, sender_address=caller_address)
r = rpc.do(o)
@@ -371,13 +376,15 @@ def cache_transfer_data(
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = ERC20.parse_transfer_request(tx['data'])
recipient_address = tx_data[0]
sender_address = tx_normalize.wallet_address(tx['from'])
recipient_address = tx_normalize.wallet_address(tx_data[0])
token_value = tx_data[1]
session = SessionBase.create_session()
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'from': sender_address,
'to': recipient_address,
'source_token': tx['to'],
'destination_token': tx['to'],
@@ -448,13 +455,14 @@ def cache_approve_data(
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx_data = ERC20.parse_approve_request(tx['data'])
recipient_address = tx_data[0]
sender_address = tx_normalize.wallet_address(tx['from'])
recipient_address = tx_normalize.wallet_address(tx_data[0])
token_value = tx_data[1]
session = SessionBase.create_session()
tx_dict = {
'hash': tx_hash_hex,
'from': tx['from'],
'from': sender_address,
'to': recipient_address,
'source_token': tx['to'],
'destination_token': tx['to'],

View File

@@ -3,10 +3,17 @@ import logging
# external imports
import celery
from hexathon import strip_0x
from chainlib.eth.constant import ZERO_ADDRESS
from hexathon import (
strip_0x,
add_0x,
)
#from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.chain import ChainSpec
from chainlib.eth.address import is_checksum_address
from chainlib.eth.address import (
is_checksum_address,
to_checksum_address,
is_address
)
from chainlib.connection import RPCConnection
from chainqueue.db.enum import StatusBits
from chainqueue.sql.tx import cache_tx_dict
@@ -21,7 +28,6 @@ from chainlib.eth.error import (
from chainlib.eth.tx import (
TxFactory,
TxFormat,
unpack,
)
from chainlib.eth.contract import (
abi_decode_single,
@@ -45,6 +51,7 @@ from cic_eth.eth.nonce import CustodialTaskNonceOracle
from cic_eth.queue.tx import (
queue_create,
register_tx,
unpack,
)
from cic_eth.queue.query import get_tx
from cic_eth.task import (
@@ -53,6 +60,11 @@ from cic_eth.task import (
CriticalSQLAlchemyAndSignerTask,
CriticalWeb3AndSignerTask,
)
from cic_eth.encode import (
tx_normalize,
ZERO_ADDRESS_NORMAL,
unpack_normal,
)
celery_app = celery.current_app
logg = logging.getLogger()
@@ -130,16 +142,16 @@ def cache_gas_data(
"""
chain_spec = ChainSpec.from_dict(chain_spec_dict)
tx_signed_raw_bytes = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack(tx_signed_raw_bytes, chain_spec)
tx = unpack_normal(tx_signed_raw_bytes, chain_spec)
session = SessionBase.create_session()
tx_dict = {
'hash': tx_hash_hex,
'hash': tx['hash'],
'from': tx['from'],
'to': tx['to'],
'source_token': ZERO_ADDRESS,
'destination_token': ZERO_ADDRESS,
'source_token': ZERO_ADDRESS_NORMAL,
'destination_token': ZERO_ADDRESS_NORMAL,
'from_value': tx['value'],
'to_value': tx['value'],
}
@@ -150,7 +162,7 @@ def cache_gas_data(
@celery_app.task(bind=True, throws=(OutOfGasError), base=CriticalSQLAlchemyAndWeb3Task)
def check_gas(self, tx_hashes, chain_spec_dict, txs=[], address=None, gas_required=MAXIMUM_FEE_UNITS):
def check_gas(self, tx_hashes_hex, chain_spec_dict, txs_hex=[], address=None, gas_required=MAXIMUM_FEE_UNITS):
"""Check the gas level of the sender address of a transaction.
If the account balance is not sufficient for the required gas, gas refill is requested and OutOfGasError raiser.
@@ -170,8 +182,23 @@ def check_gas(self, tx_hashes, chain_spec_dict, txs=[], address=None, gas_requir
:return: Signed raw transaction data list
:rtype: param txs, unchanged
"""
rpc_format_address = None
if address != None:
if not is_address(address):
raise ValueError('invalid address {}'.format(address))
address = tx_normalize.wallet_address(address)
address = add_0x(address)
tx_hashes = []
txs = []
for tx_hash in tx_hashes_hex:
tx_hash = tx_normalize.tx_hash(tx_hash)
tx_hashes.append(tx_hash)
for tx in txs_hex:
tx = tx_normalize.tx_wire(tx)
txs.append(tx)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
logg.debug('txs {} tx_hashes {}'.format(txs, tx_hashes))
addresspass = None
if len(txs) == 0:
@@ -187,8 +214,7 @@ def check_gas(self, tx_hashes, chain_spec_dict, txs=[], address=None, gas_requir
raise ValueError('txs passed to check gas must all have same sender; had {} got {}'.format(address, tx['from']))
addresspass.append(address)
if not is_checksum_address(address):
raise ValueError('invalid address {}'.format(address))
rpc_format_address = add_0x(to_checksum_address(address))
queue = self.request.delivery_info.get('routing_key')
@@ -196,7 +222,7 @@ def check_gas(self, tx_hashes, chain_spec_dict, txs=[], address=None, gas_requir
gas_balance = 0
try:
o = balance(address)
o = balance(rpc_format_address)
r = conn.do(o)
conn.disconnect()
gas_balance = abi_decode_single(ABIContractType.UINT256, r)
@@ -304,6 +330,7 @@ def refill_gas(self, recipient_address, chain_spec_dict):
# Determine value of gas tokens to send
# if an uncompleted gas refill for the same recipient already exists, we still need to spend the nonce
# however, we will perform a 0-value transaction instead
recipient_address = tx_normalize.wallet_address(recipient_address)
zero_amount = False
session = SessionBase.create_session()
status_filter = StatusBits.FINAL | StatusBits.NODE_ERROR | StatusBits.NETWORK_ERROR | StatusBits.UNKNOWN_ERROR
@@ -378,6 +405,7 @@ def resend_with_higher_gas(self, txold_hash_hex, chain_spec_dict, gas=None, defa
:returns: Transaction hash
:rtype: str, 0x-hex
"""
txold_hash_hex = tx_normalize.tx_hash(txold_hash_hex)
session = SessionBase.create_session()
otx = Otx.load(txold_hash_hex, session)

View File

@@ -2,8 +2,9 @@
from chainlib.eth.constant import ZERO_ADDRESS
from chainlib.status import Status as TxStatus
from cic_eth_registry.erc20 import ERC20Token
from hexathon import add_0x
# local imports
# local impor:ts
from cic_eth.ext.address import translate_address
@@ -44,8 +45,8 @@ class ExtendedTx:
destination = source
if destination_value == None:
destination_value = source_value
st = ERC20Token(self.chain_spec, self.rpc, source)
dt = ERC20Token(self.chain_spec, self.rpc, destination)
st = ERC20Token(self.chain_spec, self.rpc, add_0x(source))
dt = ERC20Token(self.chain_spec, self.rpc, add_0x(destination))
self.source_token = source
self.source_token_symbol = st.symbol
self.source_token_name = st.name

View File

@@ -3,11 +3,12 @@ import logging
# external imports
import celery
from chainlib.eth.address import is_checksum_address
from chainlib.eth.address import is_checksum_address, is_address, strip_0x
# local imports
from cic_eth.db.models.role import AccountRole
from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db.models.nonce import (
Nonce,
@@ -42,7 +43,8 @@ class CustodialTaskNonceOracle():
:returns: Nonce
:rtype: number
"""
r = NonceReservation.release(self.address, self.uuid, session=self.session)
address = tx_normalize.wallet_address(self.address)
r = NonceReservation.release(address, self.uuid, session=self.session)
return r[1]
@@ -58,17 +60,18 @@ def reserve_nonce(self, chained_input, chain_spec_dict, signer_address=None):
address = chained_input
logg.debug('non-explicit address for reserve nonce, using arg head {}'.format(chained_input))
else:
if is_checksum_address(signer_address):
if is_address(signer_address):
address = signer_address
logg.debug('explicit address for reserve nonce {}'.format(signer_address))
else:
address = AccountRole.get_address(signer_address, session=session)
logg.debug('role for reserve nonce {} -> {}'.format(signer_address, address))
if not is_checksum_address(address):
if not is_address(address):
raise ValueError('invalid result when resolving address for nonce {}'.format(address))
root_id = self.request.root_id
address = tx_normalize.wallet_address(address)
r = NonceReservation.next(address, root_id, session=session)
logg.debug('nonce {} reserved for address {} task {}'.format(r[1], address, r[0]))

View File

@@ -32,6 +32,7 @@ from potaahto.symbols import snake_and_camel
from cic_eth.queue.time import tx_times
from cic_eth.task import BaseTask
from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
logg = logging.getLogger()
@@ -134,7 +135,7 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict):
tx_address = transfer_data[0]
tx_token_value = transfer_data[1]
if address == tx_address:
if tx_normalize.wallet_address(address) == tx_normalize.wallet_address(tx_address):
status = StatusEnum.SENT
try:
o = receipt(tx['hash'])
@@ -152,8 +153,8 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict):
times = tx_times(tx['hash'], chain_spec)
tx_r = {
'hash': tx['hash'],
'sender': tx['from'],
'recipient': tx_address,
'sender': tx_normalize.wallet_address(tx['from']),
'recipient': tx_normalize.wallet_address(tx_address),
'source_value': tx_token_value,
'destination_value': tx_token_value,
'source_token': tx['to'],
@@ -164,10 +165,10 @@ def list_tx_by_bloom(self, bloomspec, address, chain_spec_dict):
tx_r['date_created'] = times['queue']
else:
tx_r['date_created'] = times['network']
txs[tx['hash']] = tx_r
txs[strip_0x(tx['hash'])] = tx_r
break
return txs
return txs
# TODO: Surely it must be possible to optimize this
@@ -230,6 +231,8 @@ def tx_collate(self, tx_batches, chain_spec_dict, offset, limit, newest_first=Tr
except UnknownContractError:
logg.error('verify failed on tx {}, skipping'.format(tx['hash']))
continue
tx['recipient'] = tx_normalize.wallet_address(tx['recipient'])
tx['sender'] = tx_normalize.wallet_address(tx['sender'])
txs.append(tx)
return txs

View File

@@ -15,6 +15,7 @@ from chainqueue.db.enum import (
# local imports
from cic_eth.db import SessionBase
from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
@@ -22,6 +23,9 @@ logg = logging.getLogger()
def __balance_outgoing_compatible(token_address, holder_address):
token_address = tx_normalize.executable_address(token_address)
holder_address = tx_normalize.wallet_address(holder_address)
session = SessionBase.create_session()
q = session.query(TxCache.from_value)
q = q.join(Otx)
@@ -58,6 +62,9 @@ def balance_outgoing(tokens, holder_address, chain_spec_dict):
def __balance_incoming_compatible(token_address, receiver_address):
token_address = tx_normalize.executable_address(token_address)
receiver_address = tx_normalize.wallet_address(receiver_address)
session = SessionBase.create_session()
q = session.query(TxCache.to_value)
q = q.join(Otx)
@@ -110,7 +117,7 @@ def assemble_balances(balances_collection):
logg.debug('received collection {}'.format(balances_collection))
for c in balances_collection:
for b in c:
address = b['address']
address = tx_normalize.executable_address(b['address'])
if tokens.get(address) == None:
tokens[address] = {
'address': address,

View File

@@ -6,6 +6,7 @@ import celery
from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db import SessionBase
from cic_eth.db.models.lock import Lock
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
@@ -21,6 +22,9 @@ def get_lock(address=None):
:returns: List of locks
:rtype: list of dicts
"""
if address != None:
address = tx_normalize.wallet_address(address)
session = SessionBase.create_session()
q = session.query(
Lock.date_created,

View File

@@ -4,8 +4,8 @@ import datetime
# external imports
import celery
from chainlib.chain import ChainSpec
from chainlib.eth.tx import unpack
import chainqueue.sql.query
from chainlib.eth.tx import unpack
from chainqueue.db.enum import (
StatusEnum,
is_alive,
@@ -20,6 +20,10 @@ from cic_eth.db.enum import LockEnum
from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db.models.lock import Lock
from cic_eth.db.models.base import SessionBase
from cic_eth.encode import (
tx_normalize,
unpack_normal,
)
celery_app = celery.current_app
@@ -27,49 +31,77 @@ celery_app = celery.current_app
@celery_app.task(base=CriticalSQLAlchemyTask)
def get_tx_cache(chain_spec_dict, tx_hash):
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
return get_tx_cache_local(chain_spec, tx_hash)
def get_tx_cache_local(chain_spec, tx_hash, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
session = SessionBase.bind_session(session)
r = chainqueue.sql.query.get_tx_cache(chain_spec, tx_hash, session=session)
session.close()
SessionBase.release_session(session)
return r
@celery_app.task(base=CriticalSQLAlchemyTask)
def get_tx(chain_spec_dict, tx_hash):
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
return get_tx_local(chain_spec, tx_hash)
def get_tx_local(chain_spec, tx_hash, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
session = SessionBase.bind_session(session)
r = chainqueue.sql.query.get_tx(chain_spec, tx_hash, session=session)
session.close()
SessionBase.release_session(session)
return r
@celery_app.task(base=CriticalSQLAlchemyTask)
def get_account_tx(chain_spec_dict, address, as_sender=True, as_recipient=True, counterpart=None):
address = tx_normalize.wallet_address(address)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
return get_account_tx_local(chain_spec, address, as_sender=as_sender, as_recipient=as_recipient, counterpart=counterpart)
def get_account_tx_local(chain_spec, address, as_sender=True, as_recipient=True, counterpart=None, session=None):
address = tx_normalize.wallet_address(address)
session = SessionBase.bind_session(session)
r = chainqueue.sql.query.get_account_tx(chain_spec, address, as_sender=True, as_recipient=True, counterpart=None, session=session)
session.close()
SessionBase.release_session(session)
return r
@celery_app.task(base=CriticalSQLAlchemyTask)
def get_upcoming_tx_nolock(chain_spec_dict, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None):
def get_upcoming_tx_nolock(chain_spec_dict, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0):
chain_spec = ChainSpec.from_dict(chain_spec_dict)
return get_upcoming_tx_nolock_local(chain_spec, status=status, not_status=not_status, recipient=recipient, before=before, limit=limit)
def get_upcoming_tx_nolock_local(chain_spec, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None):
recipient = tx_normalize.wallet_address(recipient)
session = SessionBase.create_session()
r = chainqueue.sql.query.get_upcoming_tx(chain_spec, status, not_status=not_status, recipient=recipient, before=before, limit=limit, session=session, decoder=unpack)
r = chainqueue.sql.query.get_upcoming_tx(chain_spec, status, not_status=not_status, recipient=recipient, before=before, limit=limit, session=session, decoder=unpack_normal)
session.close()
return r
def get_status_tx(chain_spec, status, not_status=None, before=None, exact=False, limit=0, session=None):
return chainqueue.sql.query.get_status_tx_cache(chain_spec, status, not_status=not_status, before=before, exact=exact, limit=limit, session=session, decoder=unpack)
return chainqueue.sql.query.get_status_tx_cache(chain_spec, status, not_status=not_status, before=before, exact=exact, limit=limit, session=session, decoder=unpack_normal)
def get_paused_tx(chain_spec, status=None, sender=None, session=None, decoder=None):
return chainqueue.sql.query.get_paused_tx_cache(chain_spec, status=status, sender=sender, session=session, decoder=unpack)
sender = tx_normalize.wallet_address(sender)
return chainqueue.sql.query.get_paused_tx_cache(chain_spec, status=status, sender=sender, session=session, decoder=unpack_normal)
def get_nonce_tx(chain_spec, nonce, sender):
return get_nonce_tx_cache(chain_spec, nonce, sender, decoder=unpack)
sender = tx_normalize.wallet_address(sender)
return get_nonce_tx_local(chain_spec, nonce, sender)
def get_nonce_tx_local(chain_spec, nonce, sender, session=None):
sender = tx_normalize.wallet_address(sender)
return chainqueue.sql.query.get_nonce_tx_cache(chain_spec, nonce, sender, decoder=unpack_normal, session=session)
def get_upcoming_tx(chain_spec, status=StatusEnum.READYSEND, not_status=None, recipient=None, before=None, limit=0, session=None):
@@ -91,6 +123,8 @@ def get_upcoming_tx(chain_spec, status=StatusEnum.READYSEND, not_status=None, re
:returns: Transactions
:rtype: dict, with transaction hash as key, signed raw transaction as value
"""
if recipient != None:
recipient = tx_normalize.wallet_address(recipient)
session = SessionBase.bind_session(session)
q_outer = session.query(
TxCache.sender,

View File

@@ -6,12 +6,14 @@ import chainqueue.sql.state
import celery
from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_sent(chain_spec_dict, tx_hash, fail=False):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_sent(chain_spec, tx_hash, fail, session=session)
@@ -21,6 +23,7 @@ def set_sent(chain_spec_dict, tx_hash, fail=False):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_final(chain_spec_dict, tx_hash, block=None, tx_index=None, fail=False):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_final(chain_spec, tx_hash, block=block, tx_index=tx_index, fail=fail, session=session)
@@ -30,6 +33,7 @@ def set_final(chain_spec_dict, tx_hash, block=None, tx_index=None, fail=False):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_cancel(chain_spec_dict, tx_hash, manual=False):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_cancel(chain_spec, tx_hash, manual, session=session)
@@ -39,6 +43,7 @@ def set_cancel(chain_spec_dict, tx_hash, manual=False):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_rejected(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_rejected(chain_spec, tx_hash, session=session)
@@ -48,6 +53,7 @@ def set_rejected(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_fubar(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_fubar(chain_spec, tx_hash, session=session)
@@ -57,6 +63,7 @@ def set_fubar(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_manual(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_manual(chain_spec, tx_hash, session=session)
@@ -66,6 +73,7 @@ def set_manual(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_ready(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_ready(chain_spec, tx_hash, session=session)
@@ -75,6 +83,7 @@ def set_ready(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_reserved(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_reserved(chain_spec, tx_hash, session=session)
@@ -84,6 +93,7 @@ def set_reserved(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def set_waitforgas(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.set_waitforgas(chain_spec, tx_hash, session=session)
@@ -93,6 +103,7 @@ def set_waitforgas(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def get_state_log(chain_spec_dict, tx_hash):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.get_state_log(chain_spec, tx_hash, session=session)
@@ -102,6 +113,7 @@ def get_state_log(chain_spec_dict, tx_hash):
@celery_app.task(base=CriticalSQLAlchemyTask)
def obsolete(chain_spec_dict, tx_hash, final):
tx_hash = tx_normalize.tx_hash(tx_hash)
chain_spec = ChainSpec.from_dict(chain_spec_dict)
session = SessionBase.create_session()
r = chainqueue.sql.state.obsolete_by_cache(chain_spec, tx_hash, final, session=session)

View File

@@ -13,6 +13,7 @@ from chainqueue.error import NotLocalTxError
# local imports
from cic_eth.task import CriticalSQLAlchemyAndWeb3Task
from cic_eth.db.models.base import SessionBase
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
@@ -20,6 +21,7 @@ logg = logging.getLogger()
def tx_times(tx_hash, chain_spec, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
session = SessionBase.bind_session(session)

View File

@@ -32,12 +32,16 @@ from cic_eth.db import SessionBase
from cic_eth.db.enum import LockEnum
from cic_eth.task import CriticalSQLAlchemyTask
from cic_eth.error import LockedError
from cic_eth.encode import tx_normalize
celery_app = celery.current_app
logg = logging.getLogger()
def queue_create(chain_spec, nonce, holder_address, tx_hash, signed_tx, session=None):
tx_hash = tx_normalize.tx_hash(tx_hash)
signed_tx = tx_normalize.tx_hash(signed_tx)
holder_address = tx_normalize.wallet_address(holder_address)
session = SessionBase.bind_session(session)
lock = Lock.check_aggregate(str(chain_spec), LockEnum.QUEUE, holder_address, session=session)
@@ -67,6 +71,8 @@ def register_tx(tx_hash_hex, tx_signed_raw_hex, chain_spec, queue, cache_task=No
:returns: Tuple; Transaction hash, signed raw transaction data
:rtype: tuple
"""
tx_hash_hex = tx_normalize.tx_hash(tx_hash_hex)
tx_signed_raw_hex = tx_normalize.tx_hash(tx_signed_raw_hex)
logg.debug('adding queue tx {}:{} -> {}'.format(chain_spec, tx_hash_hex, tx_signed_raw_hex))
tx_signed_raw = bytes.fromhex(strip_0x(tx_signed_raw_hex))
tx = unpack(tx_signed_raw, chain_spec)

View File

@@ -101,14 +101,14 @@ class DispatchSyncer:
LockEnum.QUEUE,
tx['from'],
],
queue=queue,
queue=config.get('CELERY_QUEUE'),
)
s_send = celery.signature(
'cic_eth.eth.tx.send',
[
self.chain_spec.asdict(),
],
queue=queue,
queue=config.get('CELERY_QUEUE'),
)
s_check.link(s_send)
t = s_check.apply_async()

View File

@@ -21,6 +21,7 @@ from erc20_faucet import Faucet
# local imports
from .base import SyncFilter
from cic_eth.eth.meta import ExtendedTx
from cic_eth.encode import tx_normalize
logg = logging.getLogger().getChild(__name__)
@@ -42,9 +43,9 @@ class CallbackFilter(SyncFilter):
return (None, None)
r = ERC20.parse_transfer_request(tx.payload)
transfer_data = {}
transfer_data['to'] = r[0]
transfer_data['to'] = tx_normalize.wallet_address(r[0])
transfer_data['value'] = r[1]
transfer_data['from'] = tx.outputs[0]
transfer_data['from'] = tx_normalize.wallet_address(tx.outputs[0])
transfer_data['token_address'] = tx.inputs[0]
return ('transfer', transfer_data)
@@ -54,8 +55,8 @@ class CallbackFilter(SyncFilter):
return (None, None)
r = ERC20.parse_transfer_from_request(tx.payload)
transfer_data = {}
transfer_data['from'] = r[0]
transfer_data['to'] = r[1]
transfer_data['from'] = tx_normalize.wallet_address(r[0])
transfer_data['to'] = tx_normalize.wallet_address(r[1])
transfer_data['value'] = r[2]
transfer_data['token_address'] = tx.inputs[0]
return ('transferfrom', transfer_data)
@@ -66,9 +67,9 @@ class CallbackFilter(SyncFilter):
return (None, None)
r = Faucet.parse_give_to_request(tx.payload)
transfer_data = {}
transfer_data['to'] = r[0]
transfer_data['to'] = tx_normalize.wallet_address(r[0])
transfer_data['value'] = tx.value
transfer_data['from'] = tx.outputs[0]
transfer_data['from'] = tx_normalize.wallet_address(tx.outputs[0])
#transfer_data['token_address'] = tx.inputs[0]
faucet_contract = tx.inputs[0]

View File

@@ -10,15 +10,14 @@ from chainlib.eth.tx import unpack
from chainqueue.db.enum import StatusBits
from chainqueue.db.models.tx import TxCache
from chainqueue.db.models.otx import Otx
from chainqueue.sql.query import get_paused_tx_cache as get_paused_tx
from chainlib.eth.address import to_checksum_address
# local imports
from cic_eth.db.models.base import SessionBase
from cic_eth.eth.gas import create_check_gas_task
from cic_eth.queue.query import get_paused_tx
from .base import SyncFilter
#logg = logging.getLogger().getChild(__name__)
logg = logging.getLogger()

View File

@@ -12,7 +12,8 @@ from hexathon import (
# local imports
from .base import SyncFilter
logg = logging.getLogger(__name__)
#logg = logging.getLogger(__name__)
logg = logging.getLogger()
account_registry_add_log_hash = '0x9cc987676e7d63379f176ea50df0ae8d2d9d1141d1231d4ce15b5965f73c9430'

View File

@@ -17,6 +17,7 @@ from cic_eth_registry import CICRegistry
from erc20_transfer_authorization import TransferAuthorization
# local imports
from cic_eth.encode import tx_normalize
from .base import SyncFilter
@@ -52,9 +53,9 @@ class TransferAuthFilter(SyncFilter):
r = TransferAuthorization.parse_create_request_request(tx.payload)
sender = r[0]
recipient = r[1]
token = r[2]
sender = tx_normalize.wallet_address(r[0])
recipient = tx_normalize.wallet_address(r[1])
token = tx_normalize.executable_address(r[2])
value = r[3]
token_data = {

View File

@@ -69,7 +69,6 @@ from cic_eth.registry import (
)
from cic_eth.task import BaseTask
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()
@@ -207,7 +206,7 @@ def main():
BaseTask.default_token_symbol = config.get('CIC_DEFAULT_TOKEN_SYMBOL')
BaseTask.default_token_address = registry.by_name(BaseTask.default_token_symbol)
default_token = ERC20Token(chain_spec, conn, BaseTask.default_token_address)
default_token = ERC20Token(chain_spec, conn, add_0x(BaseTask.default_token_address))
default_token.load(conn)
BaseTask.default_token_decimals = default_token.decimals
BaseTask.default_token_name = default_token.name

View File

@@ -18,7 +18,7 @@ from cic_eth.db.models.base import SessionBase
logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger()
arg_flags = cic_eth.cli.argflag_std_base
arg_flags = cic_eth.cli.argflag_std_base | cic_eth.cli.Flag.UNSAFE | cic_eth.cli.Flag.CHAIN_SPEC
local_arg_flags = cic_eth.cli.argflag_local_taskcallback
argparser = cic_eth.cli.ArgumentParser(arg_flags)
argparser.add_positional('tag', type=str, help='address tag')

View File

@@ -13,7 +13,6 @@ from chainlib.eth.nonce import RPCNonceOracle
from chainlib.eth.gas import RPCGasOracle
from cic_eth_registry import CICRegistry
from cic_eth_registry.error import UnknownContractError
import liveness.linux
# local imports
from cic_eth.error import SeppukuError
@@ -48,6 +47,7 @@ class BaseTask(celery.Task):
def on_failure(self, exc, task_id, args, kwargs, einfo):
if isinstance(exc, SeppukuError):
import liveness.linux
liveness.linux.reset(rundir=self.run_dir)
logg.critical(einfo)
msg = 'received critical exception {}, calling shutdown'.format(str(exc))

View File

@@ -9,8 +9,8 @@ import semver
version = (
0,
12,
2,
'alpha.4',
4,
'alpha.8',
)
version_object = semver.VersionInfo(

View File

@@ -1,8 +1,6 @@
@node cic-eth configuration
@section Configuration
(refer to @code{cic-base} for a general overview of the config pipeline)
Configuration parameters are grouped by configuration filename.
@@ -40,7 +38,26 @@ Boolean value. If set, the amount of available context for a task in the result
@subsection database
See ref cic-base when ready
@table @var
@item host
Database host
@item port
Database port
@item name
Database name
@item user
Database user
@item password
Database password
@item engine
The engine part of the dsn connection string (@code{postgresql} in @code{postgresql+psycopg2})
@item driver
The driver part of the dsn connection string (@code{psycopg2} in @code{postgresql+psycopg2})
@item pool_size
Connection pool size for database drivers that provide connection pooling
@item debug
Output actual sql queries to logs. Potentially very verbose
@end table
@subsection eth

View File

@@ -8,30 +8,44 @@ FROM registry.gitlab.com/grassrootseconomics/cic-base-images:python-3.8.6-dev-55
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
ARG EXTRA_PIP_ARGS=""
#RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
# pip install --index-url https://pypi.org/simple \
# --force-reinstall \
# --extra-index-url $GITLAB_PYTHON_REGISTRY --extra-index-url $EXTRA_INDEX_URL \
# -r requirements.txt
# -r requirements.txt
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
cic-eth-aux-erc20-demurrage-token~=0.0.2a6
COPY *requirements.txt ./
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
-r requirements.txt \
-r services_requirements.txt \
-r admin_requirements.txt
-r admin_requirements.txt
# always install the latest signer
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
$EXTRA_PIP_ARGS \
crypto-dev-signer
COPY . .
RUN python setup.py install
ENV PYTHONPATH .
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
pip install --index-url https://pypi.org/simple \
--extra-index-url $GITLAB_PYTHON_REGISTRY \
--extra-index-url $EXTRA_INDEX_URL \
cic-eth-aux-erc20-demurrage-token~=0.0.2a6
COPY docker/entrypoints/* ./
RUN chmod 755 *.sh

View File

@@ -5,27 +5,27 @@ set -e
# set CONFINI_ENV_PREFIX to override the env prefix to override env vars
echo "!!! starting signer"
python /usr/local/bin/crypto-dev-daemon -c /usr/local/etc/crypto-dev-signer -vv 2> /tmp/signer.log &
#echo "!!! starting signer"
#python /usr/local/bin/crypto-dev-daemon -c /usr/local/etc/crypto-dev-signer -vv 2> /tmp/signer.log &
echo "!!! starting taskerd"
/usr/local/bin/cic-eth-taskerd $@
# thanks! https://docs.docker.com/config/containers/multi-service_container/
sleep 1;
echo "!!! entering monitor loop"
while true; do
ps aux | grep crypto-dev-daemon | grep -q -v grep
PROCESS_1_STATUS=$?
ps aux | grep cic-eth-tasker |grep -q -v grep
PROCESS_2_STATUS=$?
# If the greps above find anything, they exit with 0 status
# If they are not both 0, then something is wrong
if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
echo "One of the processes has already exited."
exit 1
fi
sleep 15;
done
#sleep 1;
#echo "!!! entering monitor loop"
#while true; do
# ps aux | grep crypto-dev-daemon | grep -q -v grep
# PROCESS_1_STATUS=$?
# ps aux | grep cic-eth-tasker |grep -q -v grep
# PROCESS_2_STATUS=$?
# # If the greps above find anything, they exit with 0 status
# # If they are not both 0, then something is wrong
# if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
# echo "One of the processes has already exited."
# exit 1
# fi
# sleep 15;
#done
#
set +e

View File

@@ -0,0 +1,11 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r admin_requirements.txt \
-r services_requirements.txt \
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -1,3 +1,4 @@
celery==4.4.7
chainlib-eth>=0.0.7a7,<0.1.0
chainlib-eth>=0.0.9rc2,<0.1.0
semver==2.13.0
crypto-dev-signer>=0.4.15rc2,<0.5.0

View File

@@ -1,15 +1,15 @@
chainqueue>=0.0.3a2,<0.1.0
chainsyncer[sql]>=0.0.6a1,<0.1.0
chainqueue>=0.0.5a1,<0.1.0
chainsyncer[sql]>=0.0.6a3,<0.1.0
alembic==1.4.2
confini>=0.3.6rc4,<0.5.0
redis==3.5.3
hexathon~=0.0.1a7
hexathon~=0.0.1a8
pycryptodome==3.10.1
liveness~=0.0.1a7
eth-address-index>=0.1.4a1,<0.2.0
eth-accounts-index>=0.0.14a1,<0.1.0
cic-eth-registry>=0.5.8a1,<0.6.0
erc20-faucet>=0.2.4a2,<0.3.0
erc20-transfer-authorization>=0.3.4a1,<0.4.0
sarafu-faucet>=0.0.5a2,<0.1.0
eth-address-index>=0.2.3a4,<0.3.0
eth-accounts-index>=0.1.2a3,<0.2.0
cic-eth-registry>=0.6.1a3,<0.7.0
erc20-faucet>=0.3.2a2,<0.4.0
erc20-transfer-authorization>=0.3.5a2,<0.4.0
sarafu-faucet>=0.0.7a2,<0.1.0
moolb~=0.1.1b2

View File

@@ -6,4 +6,4 @@ pytest-redis==2.0.0
redis==3.5.3
eth-tester==0.5.0b3
py-evm==0.3.0a20
eth-erc20~=0.0.12a1
eth-erc20~=0.1.2a2

View File

@@ -18,7 +18,10 @@ from eth_erc20 import ERC20
from sarafu_faucet import MinterFaucet
from eth_accounts_index.registry import AccountRegistry
from potaahto.symbols import snake_and_camel
from hexathon import add_0x
from hexathon import (
add_0x,
strip_0x,
)
# local imports
from cic_eth.runnable.daemons.filters.callback import CallbackFilter
@@ -160,7 +163,7 @@ def test_faucet_gift_to_tx(
assert transfer_data['token_address'] == foo_token
def test_callback_filter(
def test_callback_filter_filter(
default_chain_spec,
init_database,
eth_rpc,
@@ -200,6 +203,7 @@ def test_callback_filter(
assert r['status'] == 1
rcpt = snake_and_camel(r)
tx.block.hash = rcpt['block_hash']
tx.apply_receipt(rcpt)
fltr = CallbackFilter(default_chain_spec, None, None, caller_address=contract_roles['CONTRACT_DEPLOYER'])
@@ -212,6 +216,7 @@ def test_callback_filter(
def call_back(self, transfer_type, result):
self.results[transfer_type] = result
logg.debug('result {}'.format(result))
return self
mock = CallbackMock()
@@ -220,4 +225,4 @@ def test_callback_filter(
fltr.filter(eth_rpc, mockblock, tx, init_database)
assert mock.results.get('transfer') != None
assert mock.results['transfer']['destination_token'] == foo_token
assert mock.results['transfer']['destination_token'] == strip_0x(foo_token)

View File

@@ -1,7 +1,6 @@
# external imports
from chainlib.connection import RPCConnection
from chainlib.eth.nonce import OverrideNonceOracle
from chainqueue.sql.tx import create as queue_create
from chainlib.eth.tx import (
TxFormat,
unpack,
@@ -26,6 +25,8 @@ from chainqueue.db.enum import StatusBits
# local imports
from cic_eth.runnable.daemons.filters.gas import GasFilter
from cic_eth.eth.gas import cache_gas_data
from cic_eth.encode import tx_normalize
from cic_eth.queue.tx import queue_create
def test_filter_gas(

View File

@@ -17,15 +17,18 @@ from chainlib.eth.block import (
block_by_number,
Block,
)
from chainlib.eth.address import (
to_checksum_address,
)
from erc20_faucet import Faucet
from hexathon import (
strip_0x,
add_0x,
)
from chainqueue.sql.query import get_account_tx
# local imports
from cic_eth.runnable.daemons.filters.register import RegistrationFilter
from cic_eth.queue.query import get_account_tx_local
logg = logging.getLogger()
@@ -69,17 +72,18 @@ def test_register_filter(
tx = Tx(tx_src, block=block, rcpt=rcpt)
tx.apply_receipt(rcpt)
fltr = RegistrationFilter(default_chain_spec, add_0x(os.urandom(20).hex()), queue=None)
fltr = RegistrationFilter(default_chain_spec, to_checksum_address(os.urandom(20).hex()), queue=None)
t = fltr.filter(eth_rpc, block, tx, db_session=init_database)
assert t == None
fltr = RegistrationFilter(default_chain_spec, account_registry, queue=None)
fltr = RegistrationFilter(default_chain_spec, to_checksum_address(account_registry), queue=None)
t = fltr.filter(eth_rpc, block, tx, db_session=init_database)
logg.debug('t {}'.format(t))
t.get_leaf()
assert t.successful()
gift_txs = get_account_tx(default_chain_spec.asdict(), agent_roles['ALICE'], as_sender=True, session=init_database)
gift_txs = get_account_tx_local(default_chain_spec, agent_roles['ALICE'], as_sender=True, session=init_database)
ks = list(gift_txs.keys())
assert len(ks) == 1
@@ -88,4 +92,4 @@ def test_register_filter(
gift_tx = unpack(tx_raw_signed_bytes, default_chain_spec)
gift = Faucet.parse_give_to_request(gift_tx['data'])
assert gift[0] == agent_roles['ALICE']
assert add_0x(gift[0]) == agent_roles['ALICE']

View File

@@ -19,6 +19,7 @@ from chainqueue.sql.query import get_account_tx
# local imports
from cic_eth.runnable.daemons.filters.transferauth import TransferAuthFilter
from cic_eth.encode import tx_normalize
def test_filter_transferauth(
@@ -66,7 +67,8 @@ def test_filter_transferauth(
t.get_leaf()
assert t.successful()
approve_txs = get_account_tx(default_chain_spec.asdict(), agent_roles['ALICE'], as_sender=True, session=init_database)
#approve_txs = get_account_tx(default_chain_spec.asdict(), agent_roles['ALICE'], as_sender=True, session=init_database)
approve_txs = get_account_tx(default_chain_spec.asdict(), tx_normalize.wallet_address(agent_roles['ALICE']), as_sender=True, session=init_database)
ks = list(approve_txs.keys())
assert len(ks) == 1
@@ -76,4 +78,4 @@ def test_filter_transferauth(
c = ERC20(default_chain_spec)
approve = c.parse_approve_request(approve_tx['data'])
assert approve[0] == agent_roles['BOB']
assert approve[0] == strip_0x(agent_roles['BOB'])

View File

@@ -0,0 +1,10 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 --extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r admin_requirements.txt
-r services_requirements.txt
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_eth --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -34,10 +34,6 @@ from chainqueue.sql.state import (
set_ready,
set_reserved,
)
from chainqueue.sql.query import (
get_tx,
get_nonce_tx_cache,
)
# local imports
from cic_eth.api.admin import AdminApi
@@ -46,6 +42,11 @@ from cic_eth.db.enum import LockEnum
from cic_eth.error import InitializationError
from cic_eth.eth.gas import cache_gas_data
from cic_eth.queue.tx import queue_create
from cic_eth.queue.query import (
get_tx,
get_nonce_tx_local,
)
from cic_eth.encode import tx_normalize
logg = logging.getLogger()
@@ -109,8 +110,8 @@ def test_tag_account(
t = api.tag_account('bar', agent_roles['CAROL'], default_chain_spec)
t.get()
assert AccountRole.get_address('foo', init_database) == agent_roles['ALICE']
assert AccountRole.get_address('bar', init_database) == agent_roles['CAROL']
assert AccountRole.get_address('foo', init_database) == tx_normalize.wallet_address(agent_roles['ALICE'])
assert AccountRole.get_address('bar', init_database) == tx_normalize.wallet_address(agent_roles['CAROL'])
def test_tx(
@@ -286,13 +287,15 @@ def test_fix_nonce(
assert t.successful()
init_database.commit()
txs = get_nonce_tx_cache(default_chain_spec, 3, agent_roles['ALICE'], session=init_database)
logg.debug('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
txs = get_nonce_tx_local(default_chain_spec, 3, agent_roles['ALICE'], session=init_database)
ks = txs.keys()
assert len(ks) == 2
for k in ks:
hsh = add_0x(k)
#hsh = add_0x(k)
hsh = tx_normalize.tx_hash(k)
otx = Otx.load(hsh, session=init_database)
init_database.refresh(otx)
logg.debug('checking nonce {} tx {} status {}'.format(3, otx.tx_hash, otx.status))

View File

@@ -30,7 +30,6 @@ from chainqueue.sql.state import (
)
from chainqueue.db.models.otx import Otx
from chainqueue.db.enum import StatusBits
from chainqueue.sql.query import get_nonce_tx_cache
from eth_erc20 import ERC20
from cic_eth_registry import CICRegistry
@@ -38,6 +37,7 @@ from cic_eth_registry import CICRegistry
from cic_eth.api.admin import AdminApi
from cic_eth.eth.gas import cache_gas_data
from cic_eth.eth.erc20 import cache_transfer_data
from cic_eth.queue.query import get_nonce_tx_local
logg = logging.getLogger()
@@ -312,7 +312,7 @@ def test_resend_inplace(
otx = Otx.load(tx_hash_hex, session=init_database)
assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
txs = get_nonce_tx_local(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
assert len(txs) == 2
@@ -363,10 +363,10 @@ def test_resend_clone(
assert otx.status & StatusBits.IN_NETWORK == StatusBits.IN_NETWORK
assert otx.status & StatusBits.OBSOLETE == StatusBits.OBSOLETE
txs = get_nonce_tx_cache(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
txs = get_nonce_tx_local(default_chain_spec, otx.nonce, agent_roles['ALICE'], session=init_database)
assert len(txs) == 1
txs = get_nonce_tx_cache(default_chain_spec, otx.nonce + 1, agent_roles['ALICE'], session=init_database)
txs = get_nonce_tx_local(default_chain_spec, otx.nonce + 1, agent_roles['ALICE'], session=init_database)
assert len(txs) == 1
otx = Otx.load(txs[0], session=init_database)

View File

@@ -10,6 +10,7 @@ from cic_eth_registry.erc20 import ERC20Token
from chainlib.chain import ChainSpec
from eth_accounts_index import AccountsIndex
from chainlib.eth.tx import (
receipt,
transaction,
)
from chainqueue.sql.state import (
@@ -29,6 +30,7 @@ def test_account_api(
init_database,
init_eth_rpc,
account_registry,
cic_registry,
custodial_roles,
celery_session_worker,
):
@@ -49,6 +51,7 @@ def test_account_api_register(
eth_rpc,
celery_session_worker,
):
api = Api(str(default_chain_spec), callback_param='accounts', callback_task='cic_eth.callbacks.noop.noop', queue=None)
t = api.create_account('')
register_tx_hash = t.get_leaf()
@@ -69,12 +72,18 @@ def test_account_api_register(
r = t.get_leaf()
assert t.successful()
o = receipt(register_tx_hash)
r = eth_rpc.do(o)
assert r['status'] == 1
o = transaction(register_tx_hash)
tx_src = eth_rpc.do(o)
c = AccountsIndex(default_chain_spec)
address = c.parse_add_request(tx_src['data'])
logg.debug('address {} '.format(address))
o = c.have(account_registry, address[0], sender_address=custodial_roles['CONTRACT_DEPLOYER'])
logg.debug('o {}'.format(o))
r = eth_rpc.do(o)
assert c.parse_have(r)

View File

@@ -3,18 +3,22 @@ import os
import logging
# external imports
import pytest
from chainlib.eth.address import to_checksum_address
from hexathon import add_0x
# local imports
from cic_eth.api.api_task import Api
logg = logging.getLogger()
def test_balance_simple_api(
default_chain_spec,
init_database,
cic_registry,
foo_token,
register_lookups,
register_tokens,
api,
celery_session_worker,
@@ -22,7 +26,7 @@ def test_balance_simple_api(
chain_str = str(default_chain_spec)
a = to_checksum_address('0x' + os.urandom(20).hex())
a = add_0x(to_checksum_address(os.urandom(20).hex()))
t = api.balance(a, 'FOO', include_pending=False)
r = t.get_leaf()
assert t.successful()
@@ -36,6 +40,7 @@ def test_balance_complex_api(
init_database,
cic_registry,
foo_token,
register_lookups,
register_tokens,
api,
celery_session_worker,
@@ -43,7 +48,7 @@ def test_balance_complex_api(
chain_str = str(default_chain_spec)
a = to_checksum_address('0x' + os.urandom(20).hex())
a = add_0x(to_checksum_address(os.urandom(20).hex()))
t = api.balance(a, 'FOO', include_pending=True)
r = t.get_leaf()
assert t.successful()

View File

@@ -6,6 +6,7 @@ import pytest
from chainlib.eth.nonce import RPCNonceOracle
from eth_erc20 import ERC20
from chainlib.eth.tx import receipt
from hexathon import strip_0x
# local imports
from cic_eth.api.api_task import Api
@@ -23,7 +24,6 @@ from cic_eth.pytest.mock.filter import (
logg = logging.getLogger()
@pytest.mark.xfail()
def test_list_tx(
default_chain_spec,
init_database,
@@ -34,8 +34,10 @@ def test_list_tx(
agent_roles,
foo_token,
register_tokens,
register_lookups,
init_eth_tester,
celery_session_worker,
init_celery_tasks,
):
tx_hashes = []
@@ -63,13 +65,16 @@ def test_list_tx(
o = receipt(tx_hash_hex)
r = eth_rpc.do(o)
assert r['status'] == 1
a = r['block_number']
block_filter.add(a.to_bytes(4, 'big'))
ab = a.to_bytes(4, 'big')
block_filter.add(ab)
a = r['block_number'] + r['transaction_index']
tx_filter.add(a.to_bytes(4, 'big'))
bb = r['transaction_index'].to_bytes(4, 'big')
cb = ab + bb
tx_filter.add(cb)
tx_hashes.append(tx_hash_hex)
tx_hashes.append(strip_0x(tx_hash_hex))
# external tx two
Nonce.next(agent_roles['ALICE'], 'foo', session=init_database)
@@ -83,26 +88,29 @@ def test_list_tx(
o = receipt(tx_hash_hex)
r = eth_rpc.do(o)
assert r['status'] == 1
a = r['block_number']
block_filter.add(a.to_bytes(4, 'big'))
ab = a.to_bytes(4, 'big')
block_filter.add(ab)
a = r['block_number'] + r['transaction_index']
tx_filter.add(a.to_bytes(4, 'big'))
bb = r['transaction_index'].to_bytes(4, 'big')
cb = ab + bb
tx_filter.add(cb)
tx_hashes.append(tx_hash_hex)
tx_hashes.append(strip_0x(tx_hash_hex))
init_eth_tester.mine_blocks(28)
# custodial tx 1
api = Api(str(default_chain_spec), queue=None)
t = api.transfer(agent_roles['ALICE'], agent_roles['CAROL'], 64, 'FOO') #, 'blinky')
t = api.transfer(agent_roles['ALICE'], agent_roles['CAROL'], 64, 'FOO')
r = t.get_leaf()
assert t.successful()
tx_hashes.append(r)
# custodial tx 2
api = Api(str(default_chain_spec), queue=None)
t = api.transfer(agent_roles['ALICE'], agent_roles['DAVE'], 16, 'FOO') #, 'blinky')
t = api.transfer(agent_roles['ALICE'], agent_roles['DAVE'], 16, 'FOO')
r = t.get_leaf()
assert t.successful()
tx_hashes.append(r)
@@ -117,7 +125,8 @@ def test_list_tx(
assert len(r) == 3
logg.debug('rrrr {}'.format(r))
logg.debug('testing against hashes {}'.format(tx_hashes))
for tx in r:
logg.debug('have tx {}'.format(tx))
tx_hashes.remove(tx['hash'])
tx_hashes.remove(strip_0x(tx['hash']))
assert len(tx_hashes) == 1

View File

@@ -10,6 +10,7 @@ from chainlib.eth.tx import (
)
from eth_erc20 import ERC20
from chainlib.eth.nonce import RPCNonceOracle
from hexathon import add_0x
# local imports
from cic_eth.db.models.nonce import (
@@ -91,5 +92,5 @@ def test_filter_process(
assert len(r) == 2
for tx_hash in r.keys():
tx_hashes.remove(tx_hash)
tx_hashes.remove(add_0x(tx_hash))
assert len(tx_hashes) == 0

View File

@@ -21,7 +21,6 @@ from chainlib.eth.constant import (
MINIMUM_FEE_UNITS,
MINIMUM_FEE_PRICE,
)
from chainqueue.sql.tx import create as queue_create
from chainqueue.sql.query import get_tx
from chainqueue.db.enum import StatusBits
from chainqueue.sql.state import (
@@ -35,6 +34,7 @@ from hexathon import strip_0x
# local imports
from cic_eth.eth.gas import cache_gas_data
from cic_eth.error import OutOfGasError
from cic_eth.queue.tx import queue_create
logg = logging.getLogger()
@@ -75,7 +75,7 @@ def test_task_check_gas_ok(
'cic_eth.eth.gas.check_gas',
[
[
tx_hash_hex,
strip_0x(tx_hash_hex),
],
default_chain_spec.asdict(),
[],
@@ -283,4 +283,3 @@ def test_task_resend_explicit(
tx_after = unpack(bytes.fromhex(strip_0x(otx.signed_tx)), default_chain_spec)
logg.debug('gasprices before {} after {}'.format(tx_before['gasPrice'], tx_after['gasPrice']))
assert tx_after['gasPrice'] > tx_before['gasPrice']

View File

@@ -51,6 +51,7 @@ def test_ext_tx_collate(
tx_hash_hex,
tx_signed_raw_hex,
)
otx.block = 666
init_database.add(otx)
init_database.commit()

View File

@@ -46,6 +46,7 @@ def test_set(
tx_hash_hex,
tx_signed_raw_hex,
)
otx.block = 666
init_database.add(otx)
init_database.commit()
@@ -74,7 +75,6 @@ def test_set(
assert (tx_stored.destination_token_address == ZERO_ADDRESS)
assert (tx_stored.from_value == tx['value'])
assert (tx_stored.to_value == to_value)
assert (tx_stored.block_number == 666)
assert (tx_stored.tx_index == 13)

View File

@@ -13,6 +13,7 @@ from cic_eth.queue.balance import (
balance_incoming,
assemble_balances,
)
from cic_eth.encode import tx_normalize
logg = logging.getLogger()
@@ -51,8 +52,8 @@ def test_assemble():
r = assemble_balances(b)
logg.debug('r {}'.format(r))
assert r[0]['address'] == token_foo
assert r[1]['address'] == token_bar
assert r[0]['address'] == tx_normalize.executable_address(token_foo)
assert r[1]['address'] == tx_normalize.executable_address(token_bar)
assert r[0].get('balance_foo') != None
assert r[0].get('balance_bar') != None
assert r[1].get('balance_baz') != None
@@ -74,11 +75,11 @@ def test_outgoing_balance(
token_address = '0x' + os.urandom(20).hex()
sender = '0x' + os.urandom(20).hex()
txc = TxCache(
tx_hash,
sender,
recipient,
token_address,
token_address,
tx_normalize.tx_hash(tx_hash),
tx_normalize.wallet_address(sender),
tx_normalize.wallet_address(recipient),
tx_normalize.executable_address(token_address),
tx_normalize.executable_address(token_address),
1000,
1000,
session=init_database,
@@ -125,11 +126,11 @@ def test_incoming_balance(
token_address = '0x' + os.urandom(20).hex()
sender = '0x' + os.urandom(20).hex()
txc = TxCache(
tx_hash,
sender,
recipient,
token_address,
token_address,
tx_normalize.tx_hash(tx_hash),
tx_normalize.wallet_address(sender),
tx_normalize.wallet_address(recipient),
tx_normalize.executable_address(token_address),
tx_normalize.executable_address(token_address),
1000,
1000,
session=init_database,

View File

@@ -21,6 +21,7 @@ from cic_eth.db.models.lock import Lock
from cic_eth.queue.query import get_upcoming_tx
from cic_eth.queue.tx import register_tx
from cic_eth.eth.gas import cache_gas_data
from cic_eth.encode import tx_normalize
# test imports
from tests.util.nonce import StaticNonceOracle
@@ -39,8 +40,8 @@ def test_upcoming_with_lock(
gas_oracle = RPCGasOracle(eth_rpc)
c = Gas(default_chain_spec, signer=eth_signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle)
alice_normal = add_0x(hex_uniform(strip_0x(agent_roles['ALICE'])))
bob_normal = add_0x(hex_uniform(strip_0x(agent_roles['BOB'])))
alice_normal = tx_normalize.wallet_address(agent_roles['ALICE'])
bob_normal = tx_normalize.wallet_address(agent_roles['BOB'])
(tx_hash_hex, tx_rpc) = c.create(alice_normal, bob_normal, 100 * (10 ** 6))
tx_signed_raw_hex = tx_rpc['params'][0]

View File

@@ -9,7 +9,7 @@ from cic_eth.db.models.lock import Lock
from cic_eth.db.enum import LockEnum
from cic_eth.error import LockedError
from cic_eth.queue.tx import queue_create
from cic_eth.encode import tx_normalize
def test_queue_lock(
init_database,
@@ -21,6 +21,8 @@ def test_queue_lock(
address = '0x' + os.urandom(20).hex()
tx_hash = '0x' + os.urandom(32).hex()
tx_raw = '0x' + os.urandom(128).hex()
address_normal = tx_normalize.wallet_address(address)
tx_hash_normal = tx_normalize.tx_hash(tx_hash)
Lock.set(chain_str, LockEnum.QUEUE)
with pytest.raises(LockedError):
@@ -32,7 +34,7 @@ def test_queue_lock(
tx_raw,
)
Lock.set(chain_str, LockEnum.QUEUE, address=address)
Lock.set(chain_str, LockEnum.QUEUE, address=address_normal)
with pytest.raises(LockedError):
queue_create(
default_chain_spec,
@@ -52,7 +54,7 @@ def test_queue_lock(
tx_raw,
)
Lock.set(chain_str, LockEnum.QUEUE, address=address, tx_hash=tx_hash)
Lock.set(chain_str, LockEnum.QUEUE, address=address_normal, tx_hash=tx_hash_normal)
with pytest.raises(LockedError):
queue_create(
default_chain_spec,
@@ -61,5 +63,3 @@ def test_queue_lock(
tx_hash,
tx_raw,
)

View File

@@ -1,8 +1,7 @@
crypto-dev-signer>=0.4.14b7,<=0.4.14
chainqueue>=0.0.3a1,<0.1.0
confini>=0.3.6rc4,<0.5.0
cic-eth-registry>=0.5.8a1,<0.6.0
crypto-dev-signer>=0.4.15a7,<=0.4.15
chainqueue>=0.0.5a1,<0.1.0
cic-eth-registry>=0.6.1a3,<0.7.0
redis==3.5.3
hexathon~=0.0.1a7
hexathon~=0.0.1a8
pycryptodome==3.10.1
pyxdg==0.27

View File

@@ -1,35 +1,15 @@
.cic_meta_variables:
variables:
APP_NAME: cic-meta
DOCKERFILE_PATH: docker/Dockerfile_ci
CONTEXT: apps/$APP_NAME
#build-mr-cic-meta:
# extends:
# - .py_build_merge_request
# - .cic_meta_variables
# rules:
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# changes:
# - apps/cic-meta/**/*
# when: always
test-mr-cic-meta:
stage: test
tags:
- integration
extends:
- .cic_meta_variables
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/$APP_NAME:$MR_IMAGE_TAG
script:
- cd /root
- npm install --dev
- npm run test
- npm run test:coverage
allow_failure: true
needs: ["build-merge-request"]
rules:
build-test-cic-meta:
stage: test
tags:
- integration
variables:
APP_NAME: cic-meta
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
script:
- cd apps/cic-meta
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile .
- docker run --entrypoint=sh $MR_IMAGE_TAG docker/run_tests.sh
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*

1
apps/cic-meta/README.md Normal file
View File

@@ -0,0 +1 @@
# CIC-Meta

View File

@@ -8,18 +8,17 @@ RUN apk add --no-cache postgresql bash
# copy the dependencies
COPY package.json package-lock.json .
RUN --mount=type=cache,mode=0755,target=/root/.npm \
RUN --mount=type=cache,id=meta,mode=0755,target=/root/.npm \
npm set cache /root/.npm && \
npm ci
COPY webpack.config.js .
COPY tsconfig.json .
## required to build the cic-client-meta module
COPY src/ src/
COPY scripts/ scripts/
COPY tests/ tests/
COPY . .
COPY tests/*.asc /root/pgp/
## copy runtime configs
COPY .config/ /usr/local/etc/cic-meta/
#

View File

@@ -0,0 +1,7 @@
#! /bin/bash
set -e
npm install --dev
npm run test
npm run test:coverage

View File

@@ -1,41 +1,17 @@
.cic_notify_variables:
variables:
APP_NAME: cic-notify
#build-mr-cic-notify:
# extends:
# - .py_build_merge_request
# - .cic_notify_variables
# rules:
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# changes:
# - apps/cic-notify/**/*
# when: always
test-mr-cic-notify:
stage: test
tags:
- integration
extends:
- .cic_notify_variables
cache:
key:
files:
- test_requirements.txt
paths:
- /root/.cache/pip
image: registry.gitlab.com/grassrootseconomics/cic-internal-integration/$APP_NAME:$MR_IMAGE_TAG
script:
- cd apps/$APP_NAME/
- >
pip install --extra-index-url https://pip.grassrootseconomics.net:8433
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple
-r test_requirements.txt
- export PYTHONPATH=. && pytest -x --cov=cic_notify --cov-fail-under=90 --cov-report term-missing tests
allow_failure: true
needs: ["build-merge-request"]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always
build-test-cic-notify:
stage: test
tags:
- integration
variables:
APP_NAME: cic-notify
MR_IMAGE_TAG: mr-$APP_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
script:
- cd apps/cic-notify
- docker build -t $MR_IMAGE_TAG -f docker/Dockerfile .
- docker run $MR_IMAGE_TAG sh docker/run_tests.sh
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- apps/$APP_NAME/**/*
when: always

View File

@@ -11,12 +11,12 @@ celery_app = celery.current_app
@celery_app.task
def persist_notification(recipient, message):
def persist_notification(message, recipient):
"""
:param recipient:
:type recipient:
:param message:
:type message:
:param recipient:
:type recipient:
:return:
:rtype:
"""

View File

@@ -11,12 +11,13 @@ local_logg = logging.getLogger(__name__)
@celery_app.task
def log(recipient, message):
def log(message, recipient):
"""
:param recipient:
:type recipient:
:param message:
:type message:
:param recipient:
:type recipient:
:return:
:rtype:
"""

View File

@@ -0,0 +1,9 @@
#! /bin/bash
set -e
pip install --extra-index-url https://pip.grassrootseconomics.net:8433 \
--extra-index-url https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple \
-r test_requirements.txt
export PYTHONPATH=. && pytest -x --cov=cic_notify --cov-fail-under=90 --cov-report term-missing tests

View File

@@ -1,18 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@@ -1,3 +0,0 @@
.idea/
dist/
node_modules/

View File

@@ -1,16 +0,0 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@@ -1,12 +0,0 @@
# Logging levels => TRACE = 0|DEBUG = 1|INFO = 2|LOG = 3|WARN = 4|ERROR = 5|FATAL = 6|OFF = 7
LOG_LEVEL=
SERVER_LOG_LEVEL=
CIC_CHAIN_ID=
CIC_LOGGING_URL=
CIC_META_URL=
CIC_KEYS_URL=
CIC_CACHE_URL=
CIC_WEB3_PROVIDER=
CIC_USSD_URL=
CIC_REGISTRY_ADDRESS=
CIC_TRUSTED_ADDRESS=

View File

@@ -1,51 +0,0 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
/tests
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
/.husky
# System Files
.DS_Store
Thumbs.db
# Configuration Files
.env

View File

@@ -1,134 +0,0 @@
stages:
- build
# - test
# - package
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
variables:
KANIKO_CACHE_ARGS: "--cache=true --cache-copy-layers=true --cache-ttl=24h"
ng_build_merge_request:
stage: build
variables:
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > "/kaniko/.docker/config.json"
- /kaniko/executor --context . $KANIKO_CACHE_ARGS --cache-repo $CI_REGISTRY_IMAGE --no-push
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: always
ng_build:
stage: build
variables:
IMAGE_TAG_BASE: $CI_REGISTRY_IMAGE:$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
LATEST_TAG: $CI_REGISTRY_IMAGE:latest
script:
- export IMAGE_TAG="$IMAGE_TAG_BASE-$(date +%s)"
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > "/kaniko/.docker/config.json"
- /kaniko/executor --context . $KANIKO_CACHE_ARGS --destination $IMAGE_TAG --destination $CI_REGISTRY_IMAGE:latest
rules:
- if: $CI_COMMIT_BRANCH == "master"
when: always
# cache:
# key:
# files:
# - package-lock.json
# paths:
# - node_modules/
# policy: pull
# image: node:alpine
# variables:
# PROJECT_PATH: "$CI_PROJECT_DIR"
# APP_OUTPUT_PATH: "$CI_PROJECT_DIR/dist/cic-staff-client"
# OUTPUT_PATH: "$CI_PROJECT_DIR/dist"
# CLI_VERSION: 10.2.0
# install_dependencies:
# stage: install
# tags:
# - docker
# script:
# - npm install -g @angular/cli@$CLI_VERSION
# - npm install
# only:
# refs:
# - merge_requests
# - master
# changes:
# - package-lock.json
# build:
# stage: build
# tags:
# - docker
# script:
# - npm ng build --prod
# after_script:
# - mv $PROJECT_PATH/nginx.conf $PROJECT_PATH/default.conf
# - cp $PROJECT_PATH/default.conf $APP_OUTPUT_PATH
# - cp $PROJECT_PATH/Dockerfile $APP_OUTPUT_PATH
# artifacts:
# name: "cic-staff-client-pipeline"
# expire_in: 1 days
# paths:
# - $APP_OUTPUT_PATH
# test:karma:
# stage: test
# allow_failure: false
# tags:
# - docker
# before_script:
# - apk add chromium
# - export CHROME_BIN=/usr/bin/chromium-browser
# script:
# - npm ng test --code-coverage --progress false --watch false --browsers=GitlabChromeHeadless
# coverage: '/Statements\s+:\s\d+.\d+%/'
# artifacts:
# name: "tests-and-coverage"
# reports:
# junit:
# - $OUTPUT_PATH/tests/junit-test-results.xml
# cobertura:
# - $OUTPUT_PATH/coverage/cobetura-coverage.xml
# paths:
# - coverage/
# test:e2e:
# stage: test
# allow_failure: false
# tags:
# - docker
# script:
# - npm ng e2e
# test:nglint:
# stage: test
# tags:
# - docker
# script:
# - npm ng lint
# docker-build:
# stage: package
# image: docker:latest
# services:
# - docker:dind
# variables:
# IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA"
# before_script:
# - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
# script:
# - docker build -t $IMAGE_TAG -f Dockerfile .
# - docker push $IMAGE_TAG
# only:
# - master

View File

@@ -1,4 +0,0 @@
package.json
package-lock.json
yarn.lock
dist

View File

@@ -1,9 +0,0 @@
{
"useTabs": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"semi": true,
"bracketSpacing": true,
"arrowParens": "always"
}

View File

@@ -1,37 +0,0 @@
# defining version of the base image
FROM node:alpine as build
# defining work directory
WORKDIR /app
# copying the json files into the image
COPY package*.json .
COPY patch-webpack.js .
# copying rest of project
RUN --mount=type=cache,target=/app/.npm \
npm set cache /app/.npm && \
npm ci
COPY . .
ARG FRONTEND_ENV=prod
# running build script
RUN npm run build:${FRONTEND_ENV}
### STAGE 2: Setup ###
# defining nginx image version
FROM nginx:alpine
## Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
# copy dist output from our first image
COPY --from=build /app/dist/cic-staff-client /usr/share/nginx/html
# copy nginx configuration file
COPY nginx.conf /etc/nginx/
EXPOSE 80
CMD [ "nginx", "-g", "daemon off;" ]

View File

@@ -1,65 +0,0 @@
# CICADA
An angular admin web client for managing users and transactions in the CIC network.
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.0.
## Angular CLI
Run `npm install -g @angular/cli` to install the angular CLI.
## Development server
Run `ng serve` for a local server, `npm run start:dev` for a dev server and `npm run start:prod` for a prod server..
Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Lazy-loading feature modules
Run `ng generate module module-name --route module-name --module app.module` to generate a new module on route `/module-name` in the app module.
## Build
Run `ng build` to build the project using local configurations.
The build artifacts will be stored in the `dist/` directory.
Use the `npm run build:dev` script for a development build and the `npm run build:prod` script for a production build.
## PWA
The app supports Progressive Web App capabilities.
Run `npm run start:pwa` to run the project in PWA mode.
PWA mode works using production configurations.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Environment variables
Default environment variables are located in the `src/environments/` directory.
Custom environment variables are contained in the `.env` file. See `.env.example` for a template.
Custom environment variables are set via the `set-env.ts` file.
Once loaded they will be populated in the directory `src/environments/`.
It contains environment variables for development on `environment.dev.ts` and production on `environment.prod.ts`.
## Code formatting
The system has automated code formatting using [Prettier](https://prettier.io/) and [TsLint](https://palantir.github.io/tslint/).
To view the styling rules set, check out `.prettierrc` and `tslint.json`.
Run `npm run format:lint` To perform formatting and linting of the codebase.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@@ -1,155 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"cic-staff-client": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss",
"changeDetection": "OnPush"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/cic-staff-client",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.js",
"node_modules/bootstrap/dist/js/bootstrap.js"
],
"webWorkerTsConfig": "tsconfig.worker.json"
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
]
},
"staging": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "cic-staff-client:build"
},
"configurations": {
"production": {
"browserTarget": "cic-staff-client:build:production"
},
"dev": {
"browserTarget": "cic-staff-client:build:dev"
},
"staging": {
"browserTarget": "cic-staff-client:build:staging"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "cic-staff-client:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"codeCoverage": true,
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json",
"tsconfig.worker.json"
],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "cic-staff-client:serve"
},
"configurations": {
"production": {
"devServerTarget": "cic-staff-client:serve:production"
}
}
}
}
}
},
"defaultProject": "cic-staff-client"
}

View File

@@ -1,866 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>AccountIndex</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_eth/accountIndex.ts</code>
</p>
<p class="comment">
<h3>Description</h3>
</p>
<p class="comment">
<p>Provides an instance of the accounts registry contract.
Allows querying of accounts that have been registered as valid accounts in the network.</p>
</p>
<p class="comment">
<h3>Example</h3>
</p>
<div class="io-description">
</div>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Properties</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#contract">contract</a>
</li>
<li>
<a href="#contractAddress">contractAddress</a>
</li>
<li>
<a href="#signerAddress">signerAddress</a>
</li>
</ul>
</td>
</tr>
<tr>
<td class="col-md-4">
<h6><b>Methods</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
<a href="#addToAccountRegistry">addToAccountRegistry</a>
</li>
<li>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
<a href="#haveAccount">haveAccount</a>
</li>
<li>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
<a href="#last">last</a>
</li>
<li>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
<a href="#totalAccounts">totalAccounts</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="constructor">Constructor</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<code>constructor(contractAddress: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank">string</a>, signerAddress?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank">string</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="26" class="link-to-prism">src/app/_eth/accountIndex.ts:26</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Create a connection to the deployed account registry contract.</p>
</div>
<div>
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>contractAddress</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
<td>
No
</td>
<td>
<code><ul>
<li>The deployed account registry contract&#39;s address.</li>
</ul>
</code>
</td>
</tr>
<tr>
<td>signerAddress</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
<td>
Yes
</td>
<td>
<code><ul>
<li>The account address of the account that deployed the account registry contract.</li>
</ul>
</code>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="inputs">
Properties
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="contract"></a>
<span class="name">
<b>
contract</b>
<a href="#contract"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >any</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="22" class="link-to-prism">src/app/_eth/accountIndex.ts:22</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>The instance of the account registry contract. </p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="contractAddress"></a>
<span class="name">
<b>
contractAddress</b>
<a href="#contractAddress"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="24" class="link-to-prism">src/app/_eth/accountIndex.ts:24</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>The deployed account registry contract&#39;s address. </p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="signerAddress"></a>
<span class="name">
<b>
signerAddress</b>
<a href="#signerAddress"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="26" class="link-to-prism">src/app/_eth/accountIndex.ts:26</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>The account address of the account that deployed the account registry contract. </p>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="methods">
Methods
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="addToAccountRegistry"></a>
<span class="name">
<b>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
addToAccountRegistry
</b>
<a href="#addToAccountRegistry"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<span class="modifier-icon icon ion-ios-reset"></span>
<code>addToAccountRegistry(address: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank">string</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="58"
class="link-to-prism">src/app/_eth/accountIndex.ts:58</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Registers an account to the accounts registry.
Requires availability of the signer address.</p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>address</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
<td>
No
</td>
<td>
<ul>
<li>The account address to be registered to the accounts registry contract.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<b>Example :</b>
<div>
<pre class="line-numbers"><code class="language-html">Prints &amp;quot;true&amp;quot; for registration of &amp;#39;0xc0ffee254729296a45a3885639AC7E10F9d54979&amp;#39;:&lt;/p&gt;
&lt;p&gt;```typescript&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;console.log(await addToAccountRegistry(&amp;#39;0xc0ffee254729296a45a3885639AC7E10F9d54979&amp;#39;));&lt;/li&gt;
&lt;li&gt;```&lt;/li&gt;
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="io-description">
<b>Returns : </b> <code>Promise&lt;boolean&gt;</code>
</div>
<div class="io-description">
<p>true - If registration is successful or account had already been registered.</p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="haveAccount"></a>
<span class="name">
<b>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
haveAccount
</b>
<a href="#haveAccount"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<span class="modifier-icon icon ion-ios-reset"></span>
<code>haveAccount(address: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank">string</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="79"
class="link-to-prism">src/app/_eth/accountIndex.ts:79</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Checks whether a specific account address has been registered in the accounts registry.
Returns &quot;true&quot; for available and &quot;false&quot; otherwise.</p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>address</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
<td>
No
</td>
<td>
<ul>
<li>The account address to be validated.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<b>Example :</b>
<div>
<pre class="line-numbers"><code class="language-html">Prints &amp;quot;true&amp;quot; or &amp;quot;false&amp;quot; depending on whether &amp;#39;0xc0ffee254729296a45a3885639AC7E10F9d54979&amp;#39; has been registered:&lt;/p&gt;
&lt;p&gt;```typescript&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;console.log(await haveAccount(&amp;#39;0xc0ffee254729296a45a3885639AC7E10F9d54979&amp;#39;));&lt;/li&gt;
&lt;li&gt;```&lt;/li&gt;
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="io-description">
<b>Returns : </b> <code>Promise&lt;boolean&gt;</code>
</div>
<div class="io-description">
<p>true - If the address has been registered in the accounts registry.</p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="last"></a>
<span class="name">
<b>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
last
</b>
<a href="#last"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<span class="modifier-icon icon ion-ios-reset"></span>
<code>last(numberOfAccounts: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank">number</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="96"
class="link-to-prism">src/app/_eth/accountIndex.ts:96</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Returns a specified number of the most recently registered accounts.</p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>numberOfAccounts</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
<td>
No
</td>
<td>
<ul>
<li>The number of accounts to return from the accounts registry.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<b>Example :</b>
<div>
<pre class="line-numbers"><code class="language-html">Prints an array of accounts:&lt;/p&gt;
&lt;p&gt;```typescript&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;console.log(await last(5));&lt;/li&gt;
&lt;li&gt;```&lt;/li&gt;
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="io-description">
<b>Returns : </b> <code>Promise&lt;Array&lt;string&gt;&gt;</code>
</div>
<div class="io-description">
<p>An array of registered account addresses.</p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="totalAccounts"></a>
<span class="name">
<b>
<span class="modifier">Public</span>
<span class="modifier">Async</span>
totalAccounts
</b>
<a href="#totalAccounts"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<span class="modifier-icon icon ion-ios-reset"></span>
<code>totalAccounts()</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="122"
class="link-to-prism">src/app/_eth/accountIndex.ts:122</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Returns the total number of accounts that have been registered in the network.</p>
</div>
<div>
<b>Example :</b>
<div>
<pre class="line-numbers"><code class="language-html">Prints the total number of registered accounts:&lt;/p&gt;
&lt;p&gt;```typescript&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;console.log(await totalAccounts());&lt;/li&gt;
&lt;li&gt;```&lt;/li&gt;
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="io-description">
<b>Returns : </b> <code>Promise&lt;number&gt;</code>
</div>
<div class="io-description">
<p>The total number of registered accounts.</p>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import Web3 from &#x27;web3&#x27;;
// Application imports
import { Web3Service } from &#x27;@app/_services/web3.service&#x27;;
import { environment } from &#x27;@src/environments/environment&#x27;;
/** Fetch the account registry contract&#x27;s ABI. */
const abi: Array&lt;any&gt; &#x3D; require(&#x27;@src/assets/js/block-sync/data/AccountsIndex.json&#x27;);
/** Establish a connection to the blockchain network. */
const web3: Web3 &#x3D; Web3Service.getInstance();
/**
* Provides an instance of the accounts registry contract.
* Allows querying of accounts that have been registered as valid accounts in the network.
*
* @remarks
* This is our interface to the accounts registry contract.
*/
export class AccountIndex {
/** The instance of the account registry contract. */
contract: any;
/** The deployed account registry contract&#x27;s address. */
contractAddress: string;
/** The account address of the account that deployed the account registry contract. */
signerAddress: string;
/**
* Create a connection to the deployed account registry contract.
*
* @param contractAddress - The deployed account registry contract&#x27;s address.
* @param signerAddress - The account address of the account that deployed the account registry contract.
*/
constructor(contractAddress: string, signerAddress?: string) {
this.contractAddress &#x3D; contractAddress;
this.contract &#x3D; new web3.eth.Contract(abi, this.contractAddress);
if (signerAddress) {
this.signerAddress &#x3D; signerAddress;
} else {
this.signerAddress &#x3D; web3.eth.accounts[0];
}
}
/**
* Registers an account to the accounts registry.
* Requires availability of the signer address.
*
* @async
* @example
* Prints &quot;true&quot; for registration of &#x27;0xc0ffee254729296a45a3885639AC7E10F9d54979&#x27;:
* &#x60;&#x60;&#x60;typescript
* console.log(await addToAccountRegistry(&#x27;0xc0ffee254729296a45a3885639AC7E10F9d54979&#x27;));
* &#x60;&#x60;&#x60;
*
* @param address - The account address to be registered to the accounts registry contract.
* @returns true - If registration is successful or account had already been registered.
*/
public async addToAccountRegistry(address: string): Promise&lt;boolean&gt; {
if (!(await this.haveAccount(address))) {
return await this.contract.methods.add(address).send({ from: this.signerAddress });
}
return true;
}
/**
* Checks whether a specific account address has been registered in the accounts registry.
* Returns &quot;true&quot; for available and &quot;false&quot; otherwise.
*
* @async
* @example
* Prints &quot;true&quot; or &quot;false&quot; depending on whether &#x27;0xc0ffee254729296a45a3885639AC7E10F9d54979&#x27; has been registered:
* &#x60;&#x60;&#x60;typescript
* console.log(await haveAccount(&#x27;0xc0ffee254729296a45a3885639AC7E10F9d54979&#x27;));
* &#x60;&#x60;&#x60;
*
* @param address - The account address to be validated.
* @returns true - If the address has been registered in the accounts registry.
*/
public async haveAccount(address: string): Promise&lt;boolean&gt; {
return (await this.contract.methods.have(address).call()) !&#x3D;&#x3D; 0;
}
/**
* Returns a specified number of the most recently registered accounts.
*
* @async
* @example
* Prints an array of accounts:
* &#x60;&#x60;&#x60;typescript
* console.log(await last(5));
* &#x60;&#x60;&#x60;
*
* @param numberOfAccounts - The number of accounts to return from the accounts registry.
* @returns An array of registered account addresses.
*/
public async last(numberOfAccounts: number): Promise&lt;Array&lt;string&gt;&gt; {
const count: number &#x3D; await this.totalAccounts();
let lowest: number &#x3D; count - numberOfAccounts;
if (lowest &lt; 0) {
lowest &#x3D; 0;
}
const accounts: Array&lt;string&gt; &#x3D; [];
for (let i &#x3D; count - 1; i &gt;&#x3D; lowest; i--) {
const account: string &#x3D; await this.contract.methods.entry(i).call();
accounts.push(account);
}
return accounts;
}
/**
* Returns the total number of accounts that have been registered in the network.
*
* @async
* @example
* Prints the total number of registered accounts:
* &#x60;&#x60;&#x60;typescript
* console.log(await totalAccounts());
* &#x60;&#x60;&#x60;
*
* @returns The total number of registered accounts.
*/
public async totalAccounts(): Promise&lt;number&gt; {
return await this.contract.methods.entryCount().call();
}
}
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'AccountIndex.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,412 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>ActivatedRouteStub</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/testing/activated-route-stub.ts</code>
</p>
<p class="comment">
<h3>Description</h3>
</p>
<p class="comment">
<p>An ActivateRoute test double with a <code>paramMap</code> observable.
Use the <code>setParamMap()</code> method to add the next <code>paramMap</code> value.</p>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Properties</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<span class="modifier">Readonly</span>
<a href="#paramMap">paramMap</a>
</li>
<li>
<span class="modifier">Private</span>
<a href="#subject">subject</a>
</li>
</ul>
</td>
</tr>
<tr>
<td class="col-md-4">
<h6><b>Methods</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#setParamMap">setParamMap</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="constructor">Constructor</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<code>constructor(initialParams?: <a href="https://angular.io/api/router/Params" target="_blank">Params</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="11" class="link-to-prism">src/testing/activated-route-stub.ts:11</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div>
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
</tr>
</thead>
<tbody>
<tr>
<td>initialParams</td>
<td>
<code><a href="https://angular.io/api/router/Params" target="_blank" >Params</a></code>
</td>
<td>
Yes
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="inputs">
Properties
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="paramMap"></a>
<span class="name">
<b>
<span class="modifier">Readonly</span>
paramMap</b>
<a href="#paramMap"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Default value : </i><code>this.subject.asObservable()</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="18" class="link-to-prism">src/testing/activated-route-stub.ts:18</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>The mock paramMap observable </p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="subject"></a>
<span class="name">
<b>
<span class="modifier">Private</span>
subject</b>
<a href="#subject"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Default value : </i><code>new ReplaySubject&lt;ParamMap&gt;()</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="11" class="link-to-prism">src/testing/activated-route-stub.ts:11</a></div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="methods">
Methods
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="setParamMap"></a>
<span class="name">
<b>
setParamMap
</b>
<a href="#setParamMap"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<code>setParamMap(params?: <a href="https://angular.io/api/router/Params" target="_blank">Params</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="21"
class="link-to-prism">src/testing/activated-route-stub.ts:21</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Set the paramMap observables&#39;s next value </p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
</tr>
</thead>
<tbody>
<tr>
<td>params</td>
<td>
<code><a href="https://angular.io/api/router/Params" target="_blank" >Params</a></code>
</td>
<td>
Yes
</td>
</tr>
</tbody>
</table>
</div>
<div>
</div>
<div class="io-description">
<b>Returns : </b> <code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >void</a></code>
</div>
<div class="io-description">
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { convertToParamMap, ParamMap, Params } from &#x27;@angular/router&#x27;;
import { ReplaySubject } from &#x27;rxjs&#x27;;
/**
* An ActivateRoute test double with a &#x60;paramMap&#x60; observable.
* Use the &#x60;setParamMap()&#x60; method to add the next &#x60;paramMap&#x60; value.
*/
export class ActivatedRouteStub {
// Use a ReplaySubject to share previous values with subscribers
// and pump new values into the &#x60;paramMap&#x60; observable
private subject &#x3D; new ReplaySubject&lt;ParamMap&gt;();
constructor(initialParams?: Params) {
this.setParamMap(initialParams);
}
/** The mock paramMap observable */
readonly paramMap &#x3D; this.subject.asObservable();
/** Set the paramMap observables&#x27;s next value */
setParamMap(params?: Params): void {
this.subject.next(convertToParamMap(params));
}
}
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'ActivatedRouteStub.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,267 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>cic-staff-client documentation</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">cic-staff-client documentation</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>AppPage</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>e2e/src/app.po.ts</code>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Methods</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#getTitleText">getTitleText</a>
</li>
<li>
<a href="#navigateTo">navigateTo</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="methods">
Methods
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="getTitleText"></a>
<span class="name">
<b>
getTitleText
</b>
<a href="#getTitleText"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<code>getTitleText()</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="8"
class="link-to-prism">e2e/src/app.po.ts:8</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description">
<b>Returns : </b> <code>Promise&lt;string&gt;</code>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="navigateTo"></a>
<span class="name">
<b>
navigateTo
</b>
<a href="#navigateTo"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<code>navigateTo()</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="4"
class="link-to-prism">e2e/src/app.po.ts:4</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description">
<b>Returns : </b> <code>Promise&lt;unknown&gt;</code>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { browser, by, element } from &#x27;protractor&#x27;;
export class AppPage {
navigateTo(): Promise&lt;unknown&gt; {
return browser.get(browser.baseUrl) as Promise&lt;unknown&gt;;
}
getTitleText(): Promise&lt;string&gt; {
return element(by.css(&#x27;app-root .content span&#x27;)).getText() as Promise&lt;string&gt;;
}
}
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'AppPage.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,369 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>BlocksBloom</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_models/transaction.ts</code>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Properties</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#alg">alg</a>
</li>
<li>
<a href="#blockFilter">blockFilter</a>
</li>
<li>
<a href="#blocktxFilter">blocktxFilter</a>
</li>
<li>
<a href="#filterRounds">filterRounds</a>
</li>
<li>
<a href="#low">low</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="inputs">
Properties
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="alg"></a>
<span class="name">
<b>
alg</b>
<a href="#alg"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="7" class="link-to-prism">src/app/_models/transaction.ts:7</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="blockFilter"></a>
<span class="name">
<b>
blockFilter</b>
<a href="#blockFilter"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="5" class="link-to-prism">src/app/_models/transaction.ts:5</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="blocktxFilter"></a>
<span class="name">
<b>
blocktxFilter</b>
<a href="#blocktxFilter"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="6" class="link-to-prism">src/app/_models/transaction.ts:6</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="filterRounds"></a>
<span class="name">
<b>
filterRounds</b>
<a href="#filterRounds"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="8" class="link-to-prism">src/app/_models/transaction.ts:8</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="low"></a>
<span class="name">
<b>
low</b>
<a href="#low"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="4" class="link-to-prism">src/app/_models/transaction.ts:4</a></div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { AccountDetails } from &#x27;@app/_models/account&#x27;;
class BlocksBloom {
low: number;
blockFilter: string;
blocktxFilter: string;
alg: string;
filterRounds: number;
}
class TxToken {
address: string;
name: string;
symbol: string;
}
class Tx {
block: number;
success: boolean;
timestamp: number;
txHash: string;
txIndex: number;
}
class Transaction {
from: string;
sender: AccountDetails;
to: string;
recipient: AccountDetails;
token: TxToken;
tx: Tx;
value: number;
type?: string;
}
class Conversion {
destinationToken: TxToken;
fromValue: number;
sourceToken: TxToken;
toValue: number;
trader: string;
user: AccountDetails;
tx: Tx;
}
export { BlocksBloom, TxToken, Tx, Transaction, Conversion };
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'BlocksBloom.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,429 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>Conversion</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_models/transaction.ts</code>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Properties</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#destinationToken">destinationToken</a>
</li>
<li>
<a href="#fromValue">fromValue</a>
</li>
<li>
<a href="#sourceToken">sourceToken</a>
</li>
<li>
<a href="#toValue">toValue</a>
</li>
<li>
<a href="#trader">trader</a>
</li>
<li>
<a href="#tx">tx</a>
</li>
<li>
<a href="#user">user</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="inputs">
Properties
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="destinationToken"></a>
<span class="name">
<b>
destinationToken</b>
<a href="#destinationToken"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="../interfaces/Token.html" target="_self" >TxToken</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="37" class="link-to-prism">src/app/_models/transaction.ts:37</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="fromValue"></a>
<span class="name">
<b>
fromValue</b>
<a href="#fromValue"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="38" class="link-to-prism">src/app/_models/transaction.ts:38</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="sourceToken"></a>
<span class="name">
<b>
sourceToken</b>
<a href="#sourceToken"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="../interfaces/Token.html" target="_self" >TxToken</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="39" class="link-to-prism">src/app/_models/transaction.ts:39</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="toValue"></a>
<span class="name">
<b>
toValue</b>
<a href="#toValue"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="40" class="link-to-prism">src/app/_models/transaction.ts:40</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="trader"></a>
<span class="name">
<b>
trader</b>
<a href="#trader"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="41" class="link-to-prism">src/app/_models/transaction.ts:41</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="tx"></a>
<span class="name">
<b>
tx</b>
<a href="#tx"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="../classes/Tx.html" target="_self" >Tx</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="43" class="link-to-prism">src/app/_models/transaction.ts:43</a></div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="user"></a>
<span class="name">
<b>
user</b>
<a href="#user"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="../interfaces/AccountDetails.html" target="_self" >AccountDetails</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="42" class="link-to-prism">src/app/_models/transaction.ts:42</a></div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { AccountDetails } from &#x27;@app/_models/account&#x27;;
class BlocksBloom {
low: number;
blockFilter: string;
blocktxFilter: string;
alg: string;
filterRounds: number;
}
class TxToken {
address: string;
name: string;
symbol: string;
}
class Tx {
block: number;
success: boolean;
timestamp: number;
txHash: string;
txIndex: number;
}
class Transaction {
from: string;
sender: AccountDetails;
to: string;
recipient: AccountDetails;
token: TxToken;
tx: Tx;
value: number;
type?: string;
}
class Conversion {
destinationToken: TxToken;
fromValue: number;
sourceToken: TxToken;
toValue: number;
trader: string;
user: AccountDetails;
tx: Tx;
}
export { BlocksBloom, TxToken, Tx, Transaction, Conversion };
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'Conversion.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,306 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>CustomErrorStateMatcher</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_helpers/custom-error-state-matcher.ts</code>
</p>
<p class="comment">
<h3>Description</h3>
</p>
<p class="comment">
<p>Custom provider that defines how form controls behave with regards to displaying error messages.</p>
</p>
<p class="comment">
<h3>Implements</h3>
</p>
<p class="comment">
<code>ErrorStateMatcher</code>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Methods</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#isErrorState">isErrorState</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="methods">
Methods
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="isErrorState"></a>
<span class="name">
<b>
isErrorState
</b>
<a href="#isErrorState"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<code>isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="17"
class="link-to-prism">src/app/_helpers/custom-error-state-matcher.ts:17</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Checks whether an invalid input has been made and an error should be made.</p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>control</td>
<td>
<code>FormControl | null</code>
</td>
<td>
No
</td>
<td>
<ul>
<li>Tracks the value and validation status of an individual form control.</li>
</ul>
</td>
</tr>
<tr>
<td>form</td>
<td>
<code>FormGroupDirective | NgForm | null</code>
</td>
<td>
No
</td>
<td>
<ul>
<li>Binding of an existing FormGroup to a DOM element.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div>
</div>
<div class="io-description">
<b>Returns : </b> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/boolean" target="_blank" >boolean</a></code>
</div>
<div class="io-description">
<p>true - If an invalid input has been made to the form control.</p>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { ErrorStateMatcher } from &#x27;@angular/material/core&#x27;;
import { FormControl, FormGroupDirective, NgForm } from &#x27;@angular/forms&#x27;;
/**
* Custom provider that defines how form controls behave with regards to displaying error messages.
*
*/
export class CustomErrorStateMatcher implements ErrorStateMatcher {
/**
* Checks whether an invalid input has been made and an error should be made.
*
* @param control - Tracks the value and validation status of an individual form control.
* @param form - Binding of an existing FormGroup to a DOM element.
* @returns true - If an invalid input has been made to the form control.
*/
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted: boolean &#x3D; form &amp;&amp; form.submitted;
return !!(control &amp;&amp; control.invalid &amp;&amp; (control.dirty || control.touched || isSubmitted));
}
}
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'CustomErrorStateMatcher.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,405 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>CustomValidator</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_helpers/custom.validator.ts</code>
</p>
<p class="comment">
<h3>Description</h3>
</p>
<p class="comment">
<p>Provides methods to perform custom validation to form inputs.</p>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Methods</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<span class="modifier">Static</span>
<a href="#passwordMatchValidator">passwordMatchValidator</a>
</li>
<li>
<span class="modifier">Static</span>
<a href="#patternValidator">patternValidator</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="methods">
Methods
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="passwordMatchValidator"></a>
<span class="name">
<b>
<span class="modifier">Static</span>
passwordMatchValidator
</b>
<a href="#passwordMatchValidator"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<span class="modifier-icon icon ion-ios-reset"></span>
<code>passwordMatchValidator(control: <a href="https://angular.io/api/forms/AbstractControl" target="_blank">AbstractControl</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="13"
class="link-to-prism">src/app/_helpers/custom.validator.ts:13</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Sets errors to the confirm password input field if it does not match with the value in the password input field.</p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>control</td>
<td>
<code><a href="https://angular.io/api/forms/AbstractControl" target="_blank" >AbstractControl</a></code>
</td>
<td>
No
</td>
<td>
<ul>
<li>The control object of the form being validated.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div>
</div>
<div class="io-description">
<b>Returns : </b> <code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >void</a></code>
</div>
<div class="io-description">
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="patternValidator"></a>
<span class="name">
<b>
<span class="modifier">Static</span>
patternValidator
</b>
<a href="#patternValidator"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<span class="modifier-icon icon ion-ios-reset"></span>
<code>patternValidator(regex: RegExp, error: <a href="https://angular.io/api/forms/ValidationErrors" target="_blank">ValidationErrors</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="28"
class="link-to-prism">src/app/_helpers/custom.validator.ts:28</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Sets errors to a form field if it does not match with the regular expression given.</p>
</div>
<div class="io-description">
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>regex</td>
<td>
<code>RegExp</code>
</td>
<td>
No
</td>
<td>
<ul>
<li>The regular expression to match with the form field.</li>
</ul>
</td>
</tr>
<tr>
<td>error</td>
<td>
<code><a href="https://angular.io/api/forms/ValidationErrors" target="_blank" >ValidationErrors</a></code>
</td>
<td>
No
</td>
<td>
<ul>
<li>Defines the map of errors to return from failed validation checks.</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div>
</div>
<div class="io-description">
<b>Returns : </b> <code>ValidationErrors | null</code>
</div>
<div class="io-description">
<p>The map of errors returned from failed validation checks.</p>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { AbstractControl, ValidationErrors } from &#x27;@angular/forms&#x27;;
/**
* Provides methods to perform custom validation to form inputs.
*/
export class CustomValidator {
/**
* Sets errors to the confirm password input field if it does not match with the value in the password input field.
*
* @param control - The control object of the form being validated.
*/
static passwordMatchValidator(control: AbstractControl): void {
const password: string &#x3D; control.get(&#x27;password&#x27;).value;
const confirmPassword: string &#x3D; control.get(&#x27;confirmPassword&#x27;).value;
if (password !&#x3D;&#x3D; confirmPassword) {
control.get(&#x27;confirmPassword&#x27;).setErrors({ NoPasswordMatch: true });
}
}
/**
* Sets errors to a form field if it does not match with the regular expression given.
*
* @param regex - The regular expression to match with the form field.
* @param error - Defines the map of errors to return from failed validation checks.
* @returns The map of errors returned from failed validation checks.
*/
static patternValidator(regex: RegExp, error: ValidationErrors): ValidationErrors | null {
return (control: AbstractControl): { [key: string]: any } &#x3D;&gt; {
if (!control.value) {
return null;
}
const valid: boolean &#x3D; regex.test(control.value);
return valid ? null : error;
};
}
}
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'CustomValidator.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

View File

@@ -1,444 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>HttpError</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_helpers/global-error-handler.ts</code>
</p>
<p class="comment">
<h3>Description</h3>
</p>
<p class="comment">
<p>A generalized http response error.</p>
</p>
<p class="comment">
<h3>Extends</h3>
</p>
<p class="comment">
<code>Error</code>
</p>
<p class="comment">
<h3>Example</h3>
</p>
<div class="io-description">
</div>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Properties</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<span class="modifier">Public</span>
<a href="#status">status</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="constructor">Constructor</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<code>constructor(message: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank">string</a>, status: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank">number</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="16" class="link-to-prism">src/app/_helpers/global-error-handler.ts:16</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Initialize the HttpError class.</p>
</div>
<div>
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>message</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string" target="_blank" >string</a></code>
</td>
<td>
No
</td>
<td>
<code><ul>
<li>The message given by the error.</li>
</ul>
</code>
</td>
</tr>
<tr>
<td>status</td>
<td>
<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
<td>
No
</td>
<td>
<code><ul>
<li>The status code given by the error.</li>
</ul>
</code>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="inputs">
Properties
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="status"></a>
<span class="name">
<b>
<span class="modifier">Public</span>
status</b>
<a href="#status"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/number" target="_blank" >number</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="16" class="link-to-prism">src/app/_helpers/global-error-handler.ts:16</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>The error&#39;s status code. </p>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">import { HttpErrorResponse } from &#x27;@angular/common/http&#x27;;
import { ErrorHandler, Injectable } from &#x27;@angular/core&#x27;;
import { Router } from &#x27;@angular/router&#x27;;
// Application imports
import { LoggingService } from &#x27;@app/_services/logging.service&#x27;;
/**
* A generalized http response error.
*
* @extends Error
*/
export class HttpError extends Error {
/** The error&#x27;s status code. */
public status: number;
/**
* Initialize the HttpError class.
*
* @param message - The message given by the error.
* @param status - The status code given by the error.
*/
constructor(message: string, status: number) {
super(message);
this.status &#x3D; status;
this.name &#x3D; &#x27;HttpError&#x27;;
}
}
/**
* Provides a hook for centralized exception handling.
*
* @extends ErrorHandler
*/
@Injectable()
export class GlobalErrorHandler extends ErrorHandler {
/**
* An array of sentence sections that denote warnings.
*/
private sentencesForWarningLogging: Array&lt;string&gt; &#x3D; [];
/**
* Initialization of the Global Error Handler.
*
* @param loggingService - A service that provides logging capabilities.
* @param router - A service that provides navigation among views and URL manipulation capabilities.
*/
constructor(private loggingService: LoggingService, private router: Router) {
super();
}
/**
* Handles different types of errors.
*
* @param error - An error objects thrown when a runtime errors occurs.
*/
handleError(error: Error): void {
this.logError(error);
const message: string &#x3D; error.message ? error.message : error.toString();
// if (error.status) {
// error &#x3D; new Error(message);
// }
const errorTraceString: string &#x3D; &#x60;Error message:\n${message}.\nStack trace: ${error.stack}&#x60;;
const isWarning: boolean &#x3D; this.isWarning(errorTraceString);
if (isWarning) {
this.loggingService.sendWarnLevelMessage(errorTraceString, { error });
} else {
this.loggingService.sendErrorLevelMessage(errorTraceString, this, { error });
}
throw error;
}
/**
* Checks if an error is of type warning.
*
* @param errorTraceString - A description of the error and it&#x27;s stack trace.
* @returns true - If the error is of type warning.
*/
private isWarning(errorTraceString: string): boolean {
let isWarning: boolean &#x3D; true;
if (errorTraceString.includes(&#x27;/src/app/&#x27;)) {
isWarning &#x3D; false;
}
this.sentencesForWarningLogging.forEach((whiteListSentence: string) &#x3D;&gt; {
if (errorTraceString.includes(whiteListSentence)) {
isWarning &#x3D; true;
}
});
return isWarning;
}
/**
* Write appropriate logs according to the type of error.
*
* @param error - An error objects thrown when a runtime errors occurs.
*/
logError(error: any): void {
const route: string &#x3D; this.router.url;
if (error instanceof HttpErrorResponse) {
this.loggingService.sendErrorLevelMessage(
&#x60;There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${
(error as HttpErrorResponse).status
}&#x60;,
this,
{ error }
);
} else if (error instanceof TypeError) {
this.loggingService.sendErrorLevelMessage(
&#x60;There was a Type error on route ${route}.\n${error.message}&#x60;,
this,
{ error }
);
} else if (error instanceof Error) {
this.loggingService.sendErrorLevelMessage(
&#x60;There was a general error on route ${route}.\n${error.message}&#x60;,
this,
{ error }
);
} else {
this.loggingService.sendErrorLevelMessage(
&#x60;Nobody threw an error but something happened on route ${route}!&#x60;,
this,
{ error }
);
}
}
}
export function rejectBody(error): { status: any; statusText: any } {
return {
status: error.status,
statusText: error.statusText,
};
}
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'HttpError.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,422 +0,0 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>CICADA</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="../images/favicon.ico">
<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top visible-xs">
<a href="../" class="navbar-brand">CICADA</a>
<button type="button" class="btn btn-default btn-menu ion-ios-menu" id="btn-menu"></button>
</div>
<div class="xs-menu menu" id="mobile-menu">
<div id="book-search-input" role="search"><input type="text" placeholder="Type to search"></div> <compodoc-menu></compodoc-menu>
</div>
<div class="container-fluid main">
<div class="row main">
<div class="hidden-xs menu">
<compodoc-menu mode="normal"></compodoc-menu>
</div>
<!-- START CONTENT -->
<div class="content class">
<div class="content-data">
<ol class="breadcrumb">
<li>Classes</li>
<li>Settings</li>
</ol>
<ul class="nav nav-tabs" role="tablist">
<li class="active">
<a href="#info" role="tab" id="info-tab" data-toggle="tab" data-link="info">Info</a>
</li>
<li >
<a href="#source" role="tab" id="source-tab" data-toggle="tab" data-link="source">Source</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="c-info">
<p class="comment">
<h3>File</h3>
</p>
<p class="comment">
<code>src/app/_models/settings.ts</code>
</p>
<p class="comment">
<h3>Description</h3>
</p>
<p class="comment">
<p>Settings class </p>
</p>
<section>
<h3 id="index">Index</h3>
<table class="table table-sm table-bordered index-table">
<tbody>
<tr>
<td class="col-md-4">
<h6><b>Properties</b></h6>
</td>
</tr>
<tr>
<td class="col-md-4">
<ul class="index-list">
<li>
<a href="#registry">registry</a>
</li>
<li>
<a href="#scanFilter">scanFilter</a>
</li>
<li>
<a href="#txHelper">txHelper</a>
</li>
<li>
<a href="#w3">w3</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="constructor">Constructor</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<code>constructor(scanFilter: <a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank">any</a>)</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="13" class="link-to-prism">src/app/_models/settings.ts:13</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Initialize the settings.</p>
</div>
<div>
<b>Parameters :</b>
<table class="params">
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Optional</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>scanFilter</td>
<td>
<code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >any</a></code>
</td>
<td>
No
</td>
<td>
<code><ul>
<li>A resource for searching through blocks on the blockchain network.</li>
</ul>
</code>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="inputs">
Properties
</h3>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="registry"></a>
<span class="name">
<b>
registry</b>
<a href="#registry"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >any</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="4" class="link-to-prism">src/app/_models/settings.ts:4</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>CIC Registry instance </p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="scanFilter"></a>
<span class="name">
<b>
scanFilter</b>
<a href="#scanFilter"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >any</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="6" class="link-to-prism">src/app/_models/settings.ts:6</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>A resource for searching through blocks on the blockchain network. </p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="txHelper"></a>
<span class="name">
<b>
txHelper</b>
<a href="#txHelper"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="https://www.typescriptlang.org/docs/handbook/basic-types.html" target="_blank" >any</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="8" class="link-to-prism">src/app/_models/settings.ts:8</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Transaction Helper instance </p>
</div>
</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-bordered">
<tbody>
<tr>
<td class="col-md-4">
<a name="w3"></a>
<span class="name">
<b>
w3</b>
<a href="#w3"><span class="icon ion-ios-link"></span></a>
</span>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Type : </i> <code><a href="../interfaces/W3.html" target="_self" >W3</a></code>
</td>
</tr>
<tr>
<td class="col-md-4">
<i>Default value : </i><code>{
engine: undefined,
provider: undefined,
}</code>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-line">Defined in <a href="" data-line="10" class="link-to-prism">src/app/_models/settings.ts:10</a></div>
</td>
</tr>
<tr>
<td class="col-md-4">
<div class="io-description"><p>Web3 Object </p>
</div>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div class="tab-pane fade tab-source-code" id="c-source">
<pre class="line-numbers compodoc-sourcecode"><code class="language-typescript">class Settings {
/** CIC Registry instance */
registry: any;
/** A resource for searching through blocks on the blockchain network. */
scanFilter: any;
/** Transaction Helper instance */
txHelper: any;
/** Web3 Object */
w3: W3 &#x3D; {
engine: undefined,
provider: undefined,
};
/**
* Initialize the settings.
*
* @param scanFilter - A resource for searching through blocks on the blockchain network.
*/
constructor(scanFilter: any) {
this.scanFilter &#x3D; scanFilter;
}
}
/** Web3 object interface */
interface W3 {
/** An active web3 instance connected to the blockchain network. */
engine: any;
/** The connection socket to the blockchain network. */
provider: any;
}
/** @exports */
export { Settings, W3 };
</code></pre>
</div>
</div>
</div><div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> result-matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
<!-- END CONTENT -->
</div>
</div>
<script>
var COMPODOC_CURRENT_PAGE_DEPTH = 1;
var COMPODOC_CURRENT_PAGE_CONTEXT = 'class';
var COMPODOC_CURRENT_PAGE_URL = 'Settings.html';
var MAX_SEARCH_RESULTS = 15;
</script>
<script src="../js/libs/custom-elements.min.js"></script>
<script src="../js/libs/lit-html.js"></script>
<!-- Required to polyfill modern browsers as code is ES5 for IE... -->
<script src="../js/libs/custom-elements-es5-adapter.js" charset="utf-8" defer></script>
<script src="../js/menu-wc.js" defer></script>
<script src="../js/libs/bootstrap-native.js"></script>
<script src="../js/libs/es6-shim.min.js"></script>
<script src="../js/libs/EventDispatcher.js"></script>
<script src="../js/libs/promise.min.js"></script>
<script src="../js/libs/zepto.min.js"></script>
<script src="../js/compodoc.js"></script>
<script src="../js/tabs.js"></script>
<script src="../js/menu.js"></script>
<script src="../js/libs/clipboard.min.js"></script>
<script src="../js/libs/prism.js"></script>
<script src="../js/sourceCode.js"></script>
<script src="../js/search/search.js"></script>
<script src="../js/search/lunr.min.js"></script>
<script src="../js/search/search-lunr.js"></script>
<script src="../js/search/search_index.js"></script>
<script src="../js/lazy-load-graphs.js"></script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More