├── .eslintrc ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── eosjs-ci │ ├── Dockerfile │ ├── contracts │ │ └── cfhello.cpp │ └── scripts │ │ └── deploy_contracts.sh └── workflows │ ├── build-docker-images.yml │ ├── ci.yml │ ├── integration-tests.yml │ ├── publish-edge.yml │ └── publish-release.yml ├── .gitignore ├── .npmignore ├── .npmrc.template ├── CONTRIBUTING.md ├── IMPORTANT.md ├── LICENSE ├── README.md ├── cypress.json ├── cypress └── integration │ └── index.spec.js ├── docs.json ├── docs ├── 01_technical-overview.md ├── 02_installation.md ├── basic-usage │ ├── 00_browser.md │ ├── 01_commonjs.md │ ├── 02_es-modules.md │ └── index.md ├── faq │ ├── 00_what-is-a-signature-provider.md │ └── 01_example-signature-providers.md ├── how-to-guides │ ├── 00_how-to-get-block-information.md │ ├── 01_how-to-submit-a-transaction.md │ ├── 02_how-to-get-transaction-information.md │ ├── 03_how-to-stake.md │ ├── 04_how-to-unstake.md │ ├── 05_how-to-create-an-account.md │ ├── 06_how-to-deploy-a-smart-contract.md │ ├── 07_how-to-get-account-information.md │ ├── 08_how-to-transfer-an-eosio-token.md │ ├── 09_how-to-get-table-information.md │ ├── 10_how-to-create-permissions.md │ ├── 11_how-to-delete-permissions.md │ ├── 12_how-to-link-permissions.md │ ├── 12_how-to-unlink-permissions.md │ ├── 13_how-to-propose-a-multisig-transaction.md │ ├── 14_how-to-approve-a-multisig-transaction.md │ ├── 15_how-to-unapprove-a-multisig-transaction.md │ ├── 16_how-to-cancel-a-multisig-transaction.md │ ├── 17_how-to-execute-a-multisig-transaction.md │ ├── 18_how-to-vote.md │ ├── 19_how-to-set-the-network.md │ └── 20_how-to-set-a-payer.md ├── index.md └── troubleshooting │ ├── 00_connectivity.md │ ├── 01_missing-authorizations.md │ └── 02_rpcerror.md ├── package.json ├── scripts ├── copy-ripe-md.js ├── is_latest.sh ├── publish-edge.sh ├── publish-tag.sh └── publish-utils.sh ├── src ├── PrivateKey.ts ├── PublicKey.ts ├── Signature.ts ├── eosjs-api-interfaces.ts ├── eosjs-api.ts ├── eosjs-ecc-migration.ts ├── eosjs-jsonrpc.ts ├── eosjs-jssig.ts ├── eosjs-key-conversions.ts ├── eosjs-numeric.ts ├── eosjs-rpc-interfaces.ts ├── eosjs-rpcerror.ts ├── eosjs-serialize.ts ├── eosjs-webauthn-sig.ts ├── index.ts ├── ripemd.es5.js ├── ripemd.js ├── rpc-web.ts └── tests │ ├── eosjs-api.test.ts │ ├── eosjs-ecc-migration.test.ts │ ├── eosjs-ecc-verification.test.js │ ├── eosjs-jsonrpc.test.ts │ ├── eosjs-jssig.test.ts │ ├── eosjs-serialize.test.ts │ ├── logo.svg │ ├── node.js │ ├── node.test.ts │ ├── setupJest.js │ ├── type-checks.test.ts │ ├── web.css │ └── web.html ├── tsconfig.json ├── tsconfig.web.json ├── typedoc.json ├── webpack.debug.js ├── webpack.prod.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@blockone/blockone", 3 | "rules": { 4 | "no-bitwise": "off", 5 | "semi": ["error", "always"], 6 | "indent": ["error", 4] 7 | }, 8 | "parserOptions": { 9 | "requireConfigFile": false 10 | }, 11 | "overrides": [ 12 | { 13 | "files": ["**/*.ts", "**/*.tsx"], 14 | "rules":{ 15 | "indent": "off", 16 | "@typescript-eslint/indent": ["error", 4], 17 | "@typescript-eslint/no-var-requires": "off", 18 | "semi": "off", 19 | "@typescript-eslint/semi": ["error", "always"] 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Version of EOSJS** 8 | _which version of eosjs exhibits the issue_ 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Change Description 5 | 6 | 7 | 8 | ## API Changes 9 | - [ ] API Changes 10 | 11 | 12 | 13 | 14 | ## Documentation Additions 15 | - [ ] Documentation Additions 16 | 17 | 18 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | target-branch: "develop" 9 | 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | target-branch: "release/22.0.x" 15 | 16 | - package-ecosystem: "github-actions" 17 | directory: "/" 18 | schedule: 19 | interval: "weekly" 20 | target-branch: "release/22.1.x" 21 | -------------------------------------------------------------------------------- /.github/eosjs-ci/Dockerfile: -------------------------------------------------------------------------------- 1 | ### Test: 2 | #### docker build --tag eosjs-ci:test ./.github/eosjs-ci 3 | #### docker run --publish 8888:8888 eosjs-ci:test 4 | 5 | ARG EOSBRANCH=develop 6 | ARG CDTBRANCH=develop 7 | FROM eosio/eosio.cdt:${CDTBRANCH} as contracts 8 | ARG CDTBRANCH 9 | WORKDIR /root 10 | RUN apt-get update \ 11 | && apt-get install -yq curl git 12 | 13 | RUN if [ "$CDTBRANCH" = "release_1.7.x" ]; then \ 14 | git clone https://github.com/EOSIO/tropical-example-web-app \ 15 | && mkdir -p /root/contracts/eosio.bios_v1.8.3 && mv ./tropical-example-web-app/eosio/contracts/eosio.bios-v1.8.3/* /root/contracts/eosio.bios_v1.8.3/ \ 16 | 17 | && git clone https://github.com/EOSIO/eos \ 18 | && cd eos \ 19 | && git checkout v2.0.12 \ 20 | && mkdir -p /root/contracts/eosio.bios/ && mv ./unittests/contracts/eosio.bios/* /root/contracts/eosio.bios/ \ 21 | && mkdir -p /root/contracts/eosio.system/ && mv ./unittests/contracts/eosio.system/* /root/contracts/eosio.system/ \ 22 | && mkdir -p /root/contracts/eosio.msig/ && mv ./unittests/contracts/eosio.msig/* /root/contracts/eosio.msig/ \ 23 | && mkdir -p /root/contracts/eosio.token/ && mv ./unittests/contracts/eosio.token/* /root/contracts/eosio.token/ \ 24 | ; fi 25 | 26 | RUN if [ "$CDTBRANCH" = "release_1.8.x" ] || [ "$CDTBRANCH" = "develop" ]; then \ 27 | git clone https://github.com/EOSIO/eos \ 28 | && cd eos \ 29 | && git checkout develop \ 30 | && mkdir -p /root/contracts/eosio.bios/ && mv ./contracts/contracts/eosio.bios/bin/* /root/contracts/eosio.bios/ \ 31 | && mkdir -p /root/contracts/eosio.boot/ && mv ./contracts/contracts/eosio.boot/bin/* /root/contracts/eosio.boot/ \ 32 | && mkdir -p /root/contracts/eosio.system/ && mv ./unittests/contracts/eosio.system/* /root/contracts/eosio.system/ \ 33 | && mkdir -p /root/contracts/eosio.msig/ && mv ./unittests/contracts/eosio.msig/* /root/contracts/eosio.msig/ \ 34 | && mkdir -p /root/contracts/eosio.token/ && mv ./unittests/contracts/eosio.token/* /root/contracts/eosio.token/ \ 35 | && mkdir -p /root/contracts/nested_container_kv/ && mv ./unittests/test-contracts/nested_container_kv/* /root/contracts/nested_container_kv \ 36 | && mkdir -p /root/contracts/nested_container_multi_index/ && mv ./unittests/test-contracts/nested_container_multi_index/* /root/contracts/nested_container_multi_index \ 37 | ; fi 38 | 39 | RUN if [ "$CDTBRANCH" = "release_1.8.x" ] || [ "$CDTBRANCH" = "develop" ]; then \ 40 | git clone https://github.com/EOSIO/eosio.cdt \ 41 | && cd eosio.cdt \ 42 | && git checkout develop \ 43 | && mkdir -p build/read_only_query_tests/ \ 44 | && eosio-cpp -abigen ./tests/unit/test_contracts/read_only_query_tests.cpp -o ./build/read_only_query_tests/read_only_query_tests.wasm \ 45 | && mkdir -p /root/contracts/read_only_query_tests/ && mv ./build/read_only_query_tests/* /root/contracts/read_only_query_tests/ \ 46 | ; fi 47 | 48 | RUN if [ "$CDTBRANCH" = "release_1.8.x" ] || [ "$CDTBRANCH" = "develop" ]; then \ 49 | git clone https://github.com/EOSIO/key-value-example-app.git \ 50 | && cd key-value-example-app \ 51 | && eosio-cpp -abigen ./contracts/kv_todo/src/kv_todo.cpp -o ./contracts/kv_todo/build/kv_todo.wasm -R ./contracts/kv_todo/ricardian/ -I ./contracts/kv_todo/include/ \ 52 | && mkdir -p /root/contracts/kv_todo/ && mv ./contracts/kv_todo/build/* /root/contracts/kv_todo/ \ 53 | ; fi 54 | 55 | RUN if [ "$CDTBRANCH" = "release_1.8.x" ] || [ "$CDTBRANCH" = "develop" ]; then \ 56 | git clone https://github.com/EOSIO/return-values-example-app.git \ 57 | && cd return-values-example-app \ 58 | && eosio-cpp -abigen ./contracts/action_return_value/src/action_return_value.cpp -o ./contracts/action_return_value/build/action_return_value.wasm -R ./contracts/action_return_value/ricardian/ \ 59 | && mkdir -p /root/contracts/action_return_value/ && mv ./contracts/action_return_value/build/* /root/contracts/action_return_value/ \ 60 | ; fi 61 | 62 | RUN mkdir cfhello 63 | COPY ./contracts/cfhello.cpp /root/cfhello 64 | RUN cd cfhello \ 65 | && mkdir build \ 66 | && eosio-cpp -abigen ./cfhello.cpp -o ./build/cfhello.wasm \ 67 | && mkdir -p /root/contracts/cfhello/ && mv ./build/* /root/contracts/cfhello/ 68 | 69 | FROM eosio/eosio:${EOSBRANCH} 70 | ARG EOSBRANCH 71 | ENTRYPOINT ["nodeos", "--data-dir", "/root/.local/share", "-e", "-p", "eosio", "--replay-blockchain", "--plugin", "eosio::producer_plugin", "--plugin", "eosio::producer_api_plugin", "--plugin", "eosio::chain_api_plugin", "--plugin", "eosio::trace_api_plugin", "--trace-no-abis", "--plugin", "eosio::db_size_api_plugin", "--plugin", "eosio::http_plugin", "--http-server-address=0.0.0.0:8888", "--access-control-allow-origin=*", "--contracts-console", "--http-validate-host=false", "--enable-account-queries=true", "--verbose-http-errors", "--max-transaction-time=100"] 72 | WORKDIR /root 73 | RUN mkdir -p "/opt/eosio/bin/contracts" 74 | COPY --from=contracts /root/contracts /opt/eosio/bin/contracts/ 75 | COPY ./ /opt/eosio/bin/ 76 | 77 | RUN mkdir -p "/opt/eosio/bin/config-dir" 78 | RUN /bin/bash /opt/eosio/bin/scripts/deploy_contracts.sh "$EOSBRANCH" 79 | -------------------------------------------------------------------------------- /.github/eosjs-ci/contracts/cfhello.cpp: -------------------------------------------------------------------------------- 1 | // Import necessary libraries 2 | #include 3 | #include 4 | 5 | using namespace eosio; 6 | 7 | class [[eosio::contract("cfhello")]] cfhello : public contract { 8 | public: 9 | using contract::contract; 10 | 11 | [[eosio::action]] 12 | void contextfree() { 13 | int cfd_index = 0; 14 | while(true) { 15 | int read_size = get_context_free_data( cfd_index, nullptr, 0 ); 16 | if (read_size == -1) { 17 | if (cfd_index == 0) { 18 | print("No context free data found"); 19 | } 20 | break; 21 | } 22 | 23 | char* context_free_data = new char[read_size]; 24 | get_context_free_data( cfd_index, context_free_data, read_size ); 25 | 26 | print("CFD ", std::to_string(cfd_index), ":", context_free_data, "\n"); 27 | cfd_index++; 28 | } 29 | } 30 | 31 | [[eosio::action]] 32 | void normal( name user ) { 33 | print( "Hi, ", user); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches-ignore: 5 | - develop 6 | pull_request: 7 | 8 | jobs: 9 | ci: 10 | name: CI 11 | runs-on: ubuntu-18.04 12 | steps: 13 | - name: Check for GIT_API_KEY 14 | id: check_token 15 | run: echo ::set-output name=token_exists::${HAS_SECRET} 16 | env: 17 | HAS_SECRET: ${{ secrets.GIT_API_KEY != null }} 18 | - name: Checkout (with GIT_API_KEY) 19 | if: ${{ steps.check_token.outputs.token_exists == 'true' }} 20 | uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f 21 | with: 22 | token: ${{ secrets.GIT_API_KEY }} 23 | - name: Checkout (with GitHub Token) 24 | if: ${{ steps.check_token.outputs.token_exists == 'false' }} 25 | uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f 26 | with: 27 | token: ${{ github.token }} 28 | - name: Setup Node.js v16.x.x 29 | uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f 30 | with: 31 | node-version: '16' 32 | registry-url: 'https://registry.npmjs.org' 33 | - name: Update 34 | run: | 35 | yarn install && yarn upgrade && npx syncyarnlock@1.0.19 -s -k && rm -rf yarn.lock && yarn install 36 | - name: Install 37 | run: | 38 | yarn --frozen-lockfile 39 | - name: Lint 40 | run: | 41 | yarn lint 42 | - name: Audit 43 | run: | 44 | yarn audit 45 | - name: Test 46 | run: | 47 | yarn test 48 | - name: Test Node 49 | run: | 50 | yarn test-node 51 | - name: Test Types 52 | run: | 53 | yarn test-types 54 | - name: Build 55 | run: | 56 | yarn build-web 57 | - name: Test Web 58 | uses: cypress-io/github-action@6122aa43014e18ec9c2d06fc0bdc5b6759064508 59 | with: 60 | spec: cypress/integration/index.spec.js 61 | - name: Get Protected Status 62 | if: github.event_name == 'push' 63 | id: protected_step 64 | run: | 65 | PROTECTED=$(curl "https://api.github.com/repos/${{ github.repository }}/branches/${GITHUB_REF#refs/*/}" 2>/dev/null | jq -r '.protected') 66 | echo ::set-output name=protected::$PROTECTED 67 | - name: Commit/Push 68 | if: github.event_name == 'push' && steps.protected_step.outputs.protected == 'false' && github.actor != 'dependabot[bot]' 69 | run: | 70 | git config --global user.name 'Block.one DevOps' 71 | git config --global user.email 'blockone-devops@users.noreply.github.com' 72 | git commit package.json yarn.lock -m "Updating package.json and yarn.lock" || echo "Nothing to commit" 73 | git push origin ${GITHUB_REF#refs/*/} 74 | services: 75 | nodeos: 76 | image: eosio/eosjs-ci:release_2.2.x 77 | 78 | ports: 79 | - 8888:8888 80 | - 9876:9876 81 | -------------------------------------------------------------------------------- /.github/workflows/publish-edge.yml: -------------------------------------------------------------------------------- 1 | name: Publish Edge 2 | on: 3 | push: 4 | branches: 5 | - develop 6 | 7 | jobs: 8 | check-tokens: 9 | name: "Check NPM Token" 10 | runs-on: ubuntu-18.04 11 | steps: 12 | - name: Check for NPM_AUTH_TOKEN 13 | id: check_token 14 | run: echo ::set-output name=token_exists::${HAS_SECRET} 15 | env: 16 | HAS_SECRET: ${{ secrets.NPM_AUTH_TOKEN != null }} 17 | - name: Succeed job on existing NPM_AUTH_TOKEN 18 | if: ${{ steps.check_token.outputs.token_exists == 'true' }} 19 | uses: actions/github-script@v3 20 | with: 21 | script: | 22 | core.setOutput('Success. NPM_AUTH_TOKEN is present in repository secrets.'); 23 | - name: Fail on missing NPM_AUTH_TOKEN 24 | if: ${{ steps.check_token.outputs.token_exists == 'false' }} 25 | uses: actions/github-script@v3 26 | with: 27 | script: | 28 | core.setFailed('Failure: No NPM_AUTH_TOKEN present in repository secrets.'); 29 | 30 | publish-edge: 31 | name: Publish Edge 32 | runs-on: ubuntu-18.04 33 | needs: check-tokens 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f 37 | - name: Setup Node.js v16.x.x 38 | uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f 39 | with: 40 | node-version: '16' 41 | registry-url: 'https://registry.npmjs.org' 42 | - name: Install 43 | run: | 44 | yarn --frozen-lockfile 45 | - name: Lint 46 | run: | 47 | yarn lint 48 | - name: Test 49 | run: | 50 | yarn test 51 | - name: Test Node 52 | run: | 53 | yarn test-node 54 | - name: Test Types 55 | run: | 56 | yarn test-types 57 | - name: Build 58 | run: | 59 | yarn build-web 60 | - name: Test Web 61 | uses: cypress-io/github-action@6122aa43014e18ec9c2d06fc0bdc5b6759064508 62 | with: 63 | spec: cypress/integration/index.spec.js 64 | - name: Publish Edge 65 | run: | 66 | . ./scripts/publish-utils.sh 67 | setup_git 68 | COMMIT=${GITHUB_SHA:0:7} 69 | sed -i "s/ \"version\": \"\([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/&-$GITHUB_RUN_NUMBER-$COMMIT/" package.json 70 | git commit -a -m "Updating version [skip ci]" --allow-empty 71 | npm publish --access public --tag edge 72 | env: 73 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 74 | 75 | services: 76 | nodeos: 77 | image: eosio/eosjs-ci:release_2.2.x 78 | 79 | ports: 80 | - 8888:8888 81 | - 9876:9876 82 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | release: 4 | types: [published] 5 | 6 | jobs: 7 | check-tokens: 8 | name: "Check NPM Token" 9 | runs-on: ubuntu-18.04 10 | steps: 11 | - name: Check for NPM_AUTH_TOKEN 12 | id: check_token 13 | run: echo ::set-output name=token_exists::${HAS_SECRET} 14 | env: 15 | HAS_SECRET: ${{ secrets.NPM_AUTH_TOKEN != null }} 16 | - name: Succeed job on existing NPM_AUTH_TOKEN 17 | if: ${{ steps.check_token.outputs.token_exists == 'true' }} 18 | uses: actions/github-script@v3 19 | with: 20 | script: | 21 | core.setOutput('Success. NPM_AUTH_TOKEN is present in repository secrets.'); 22 | - name: Fail on missing NPM_AUTH_TOKEN 23 | if: ${{ steps.check_token.outputs.token_exists == 'false' }} 24 | uses: actions/github-script@v3 25 | with: 26 | script: | 27 | core.setFailed('Failure: No NPM_AUTH_TOKEN present in repository secrets.'); 28 | 29 | publish-release: 30 | if: "!github.event.release.prerelease" 31 | name: Publish Release 32 | runs-on: ubuntu-18.04 33 | needs: check-tokens 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f 37 | - name: Setup Node.js v16.x.x 38 | uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f 39 | with: 40 | node-version: '16' 41 | registry-url: 'https://registry.npmjs.org' 42 | - name: Install 43 | run: | 44 | yarn --frozen-lockfile 45 | - name: Lint 46 | run: | 47 | yarn lint 48 | - name: Test 49 | run: | 50 | yarn test 51 | - name: Test Node 52 | run: | 53 | yarn test-node 54 | - name: Test Types 55 | run: | 56 | yarn test-types 57 | - name: Build 58 | run: | 59 | yarn build-web 60 | - name: Test Web 61 | uses: cypress-io/github-action@6122aa43014e18ec9c2d06fc0bdc5b6759064508 62 | with: 63 | spec: cypress/integration/index.spec.js 64 | - name: Publish Release 65 | run: | 66 | . ./scripts/publish-utils.sh 67 | setup_git 68 | ensure_version_match 69 | git commit -a -m "Updating version [skip ci]" --allow-empty 70 | npm publish --access public 71 | env: 72 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 73 | 74 | services: 75 | nodeos: 76 | image: eosio/eosjs-ci:release_2.2.x 77 | 78 | ports: 79 | - 8888:8888 80 | - 9876:9876 81 | 82 | publish-rc: 83 | if: "github.event.release.prerelease" 84 | name: Publish RC 85 | runs-on: ubuntu-18.04 86 | needs: check-tokens 87 | steps: 88 | - name: Checkout 89 | uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f 90 | - name: Setup Node.js v16.x.x 91 | uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f 92 | with: 93 | node-version: '16' 94 | registry-url: 'https://registry.npmjs.org' 95 | - name: Install 96 | run: | 97 | yarn --frozen-lockfile 98 | - name: Lint 99 | run: | 100 | yarn lint 101 | - name: Test 102 | run: | 103 | yarn test 104 | - name: Test Node 105 | run: | 106 | yarn test-node 107 | - name: Test Types 108 | run: | 109 | yarn test-types 110 | - name: Build 111 | run: | 112 | yarn build-web 113 | - name: Test Web 114 | uses: cypress-io/github-action@6122aa43014e18ec9c2d06fc0bdc5b6759064508 115 | with: 116 | spec: cypress/integration/index.spec.js 117 | - name: Publish RC 118 | run: | 119 | . ./scripts/publish-utils.sh 120 | setup_git 121 | ensure_version_match 122 | git commit -a -m "Updating version [skip ci]" --allow-empty 123 | npm publish --access public --tag RC 124 | env: 125 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 126 | 127 | services: 128 | nodeos: 129 | image: eosio/eosjs-ci:release_2.2.x 130 | 131 | ports: 132 | - 8888:8888 133 | - 9876:9876 134 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .vscode 4 | dist/ 5 | dist-web/ 6 | node_modules/ 7 | docs-build/ 8 | *.tgz 9 | .github/**/*.wasm 10 | .github/**/*.abi 11 | 12 | #cypress artifacts 13 | cypress/screenshots/ 14 | cypress/videos/ 15 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Exclude all files by default 2 | * 3 | 4 | # Include distribution bundle but exclude test files if they are built into dist 5 | !dist/** 6 | *.test.* 7 | 8 | # Include documentation and version information in bundle 9 | !CONTRIBUTING.md 10 | 11 | # Include any additional source files which should be bundled 12 | !src/**/*.abi.json 13 | -------------------------------------------------------------------------------- /.npmrc.template: -------------------------------------------------------------------------------- 1 | //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to EOSJS 2 | 3 | Interested in contributing? That's awesome! Here are some guidelines to get started quickly and easily: 4 | 5 | - [Reporting An Issue](#reporting-an-issue) 6 | - [Bug Reports](#bug-reports) 7 | - [Feature Requests](#feature-requests) 8 | - [Change Requests](#change-requests) 9 | - [Working on EOSJS](#working-on-eosjs) 10 | - [Feature Branches](#feature-branches) 11 | - [Submitting Pull Requests](#submitting-pull-requests) 12 | - [Testing](#testing) 13 | - [Quality Assurance](#quality-assurance) 14 | - [Conduct](#conduct) 15 | - [Contributor License & Acknowledgments](#contributor-license--acknowledgments) 16 | - [References](#references) 17 | 18 | ## Reporting An Issue 19 | 20 | If you're about to raise an issue because you think you've found a problem with EOSJS, or you'd like to make a request for a new feature in the codebase, or any other reason… please read this first. 21 | 22 | The GitHub issue tracker is the preferred channel for [bug reports](#bug-reports), [feature requests](#feature-requests), and [submitting pull requests](#submitting-pull-requests), but please respect the following restrictions: 23 | 24 | * Please **search for existing issues**. Help us keep duplicate issues to a minimum by checking to see if someone has already reported your problem or requested your idea. 25 | 26 | * Please **be civil**. Keep the discussion on topic and respect the opinions of others. See also our [Contributor Code of Conduct](#conduct). 27 | 28 | ### Bug Reports 29 | 30 | A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful - thank you! 31 | 32 | Guidelines for bug reports: 33 | 34 | 1. **Use the GitHub issue search** — check if the issue has already been 35 | reported. 36 | 37 | 1. **Check if the issue has been fixed** — look for [closed issues in the 38 | current milestone](https://github.com/EOSIO/eosjs/issues?q=is%3Aissue+is%3Aclosed) or try to reproduce it 39 | using the latest `develop` branch. 40 | 41 | A good bug report shouldn't leave others needing to chase you up for more information. Be sure to include the details of your environment and relevant tests that demonstrate the failure. 42 | 43 | [Report a bug](https://github.com/EOSIO/eosjs/issues/new?template=bug_report.md) 44 | 45 | ### Feature Requests 46 | 47 | Feature requests are welcome. Before you submit one be sure to have: 48 | 49 | 1. **Use the GitHub search** and check the feature hasn't already been requested. 50 | 1. Take a moment to think about whether your idea fits with the scope and aims of the project. 51 | 1. Remember, it's up to *you* to make a strong case to convince the project's leaders of the merits of this feature. Please provide as much detail and context as possible, this means explaining the use case and why it is likely to be common. 52 | 53 | ### Change Requests 54 | 55 | Change requests cover both architectural and functional changes to how EOSJS works. If you have an idea for a new or different dependency, a refactor, or an improvement to a feature, etc - please be sure to: 56 | 57 | 1. **Use the GitHub search** and check someone else didn't get there first 58 | 1. Take a moment to think about the best way to make a case for, and explain what you're thinking. Are you sure this shouldn't really be 59 | a [bug report](#bug-reports) or a [feature request](#feature-requests)? Is it really one idea or is it many? What's the context? What problem are you solving? Why is what you are suggesting better than what's already there? 60 | 61 | ## Working on EOSJS 62 | 63 | Code contributions are welcome and encouraged! If you are looking for a good place to start, check out the [good first issue](https://github.com/EOSIO/eosjs/labels/good%20first%20issue) label in GitHub issues. 64 | 65 | Also, please follow these guidelines when submitting code: 66 | 67 | ### Feature Branches 68 | 69 | To get it out of the way: 70 | 71 | - **[develop](https://github.com/EOSIO/eosjs/tree/develop)** is the development branch. All work on the next release happens here so you should generally branch off `develop`. Do **NOT** use this branch for a production site. 72 | - **[master](https://github.com/EOSIO/eosjs/tree/master)** contains the latest release of EOSJS. This branch may be used in production. Do **NOT** use this branch to work on EOSJS's source. 73 | 74 | ### Submitting Pull Requests 75 | 76 | Pull requests are awesome. If you're looking to raise a PR for something which doesn't have an open issue, please think carefully about [raising an issue](#reporting-an-issue) which your PR can close, especially if you're fixing a bug. This makes it more likely that there will be enough information available for your PR to be properly tested and merged. 77 | 78 | ### Testing 79 | 80 | EOSJS is used by many libraries across the EOSIO ecosystem, so proper testing is absolutely essential prior to opening a pull request. This can be done in EOSJS by running `yarn build-production`. This command will build the distrubution bundles (`yarn build-all`) and test each environment accordingly (`yarn test-all`). 81 | 82 | #### Automated Unit Test Suite 83 | 84 | `yarn test` will run through the core functionality of each EOSJS module with Jest. 85 | 86 | #### Integration Test Suite 87 | 88 | Integration tests will only work with a local node running on port 8888 and with test accounts "bob" and "alice". This can be accomplished by following the [EOSIO Developer Getting Started Guide](https://developers.eos.io/eosio-home/docs/getting-the-software#section-step-1-1-start-keosd). 89 | 90 | ##### Web Environment 91 | 92 | Run `yarn build-web` to create the `dist-web` folder and web distrubution modules then `yarn test-web`. This will run through the `tests/web.html` file using Cypress to inform you on the command line of any test failures. 93 | 94 | ##### NodeJS Environment 95 | 96 | Run `yarn build` to build the NPM distribution bundle then run `yarn test-node`. This will create an out of box node environment with `tests/node.js` then test that environment with Jest and relay the results to the command line. 97 | 98 | ### Quality Assurance 99 | 100 | Never underestimate just how useful quality assurance is. If you're looking to get involved with the code base and don't know where to start, checking out and testing a pull request is one of the most useful things you could do. 101 | 102 | Essentially, [check out the latest develop branch](#working-on-eosjs), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! 103 | 104 | ## Conduct 105 | 106 | While contributing, please be respectful and constructive, so that participation in our project is a positive experience for everyone. 107 | 108 | Examples of behavior that contributes to creating a positive environment include: 109 | - Using welcoming and inclusive language 110 | - Being respectful of differing viewpoints and experiences 111 | - Gracefully accepting constructive criticism 112 | - Focusing on what is best for the community 113 | - Showing empathy towards other community members 114 | 115 | Examples of unacceptable behavior include: 116 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 117 | - Trolling, insulting/derogatory comments, and personal or political attacks 118 | - Public or private harassment 119 | - Publishing others’ private information, such as a physical or electronic address, without explicit permission 120 | - Other conduct which could reasonably be considered inappropriate in a professional setting 121 | 122 | ## Contributor License & Acknowledgments 123 | 124 | Whenever you make a contribution to this project, you license your contribution under the same terms as set out in LICENSE, and you represent and warrant that you have the right to license your contribution under those terms. Whenever you make a contribution to this project, you also certify in the terms of the Developer’s Certificate of Origin set out below: 125 | 126 | ``` 127 | Developer Certificate of Origin 128 | Version 1.1 129 | 130 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 131 | 1 Letterman Drive 132 | Suite D4700 133 | San Francisco, CA, 94129 134 | 135 | Everyone is permitted to copy and distribute verbatim copies of this 136 | license document, but changing it is not allowed. 137 | 138 | 139 | Developer's Certificate of Origin 1.1 140 | 141 | By making a contribution to this project, I certify that: 142 | 143 | (a) The contribution was created in whole or in part by me and I 144 | have the right to submit it under the open source license 145 | indicated in the file; or 146 | 147 | (b) The contribution is based upon previous work that, to the best 148 | of my knowledge, is covered under an appropriate open source 149 | license and I have the right under that license to submit that 150 | work with modifications, whether created in whole or in part 151 | by me, under the same open source license (unless I am 152 | permitted to submit under a different license), as indicated 153 | in the file; or 154 | 155 | (c) The contribution was provided directly to me by some other 156 | person who certified (a), (b) or (c) and I have not modified 157 | it. 158 | 159 | (d) I understand and agree that this project and the contribution 160 | are public and that a record of the contribution (including all 161 | personal information I submit with it, including my sign-off) is 162 | maintained indefinitely and may be redistributed consistent with 163 | this project or the open source license(s) involved. 164 | ``` 165 | 166 | ## References 167 | 168 | * Overall CONTRIB adapted from https://github.com/mathjax/MathJax/blob/master/CONTRIBUTING.md 169 | * Conduct section adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 170 | -------------------------------------------------------------------------------- /IMPORTANT.md: -------------------------------------------------------------------------------- 1 | # Important Notice 2 | 3 | We (block.one and its affiliates) make available EOSIO and other software, updates, patches and documentation (collectively, Software) on a voluntary basis as a member of the EOSIO community. A condition of you accessing any Software, websites, articles, media, publications, documents or other material (collectively, Material) is your acceptance of the terms of this important notice. 4 | 5 | ## Software 6 | We are not responsible for ensuring the overall performance of Software or any related applications. Any test results or performance figures are indicative and will not reflect performance under all conditions. Software may contain components that are open sourced and subject to their own licenses; you are responsible for ensuring your compliance with those licenses. 7 | 8 | We make no representation, warranty, guarantee or undertaking in respect of Software, whether expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software. 9 | 10 | Wallets and related components are complex software that require the highest levels of security. If incorrectly built or used, they may compromise users’ private keys and digital assets. Wallet applications and related components should undergo thorough security evaluations before being used. Only experienced developers should work with such Software. 11 | 12 | Material is not made available to any person or entity that is the subject of sanctions administered or enforced by any country or government or otherwise designated on any list of prohibited or restricted parties (including but not limited to the lists maintained by the United Nations Security Council, the U.S. Government, the European Union or its Member States, or other applicable government authority) or organized or resident in a country or territory that is the subject of country-wide or territory-wide sanctions. You represent and warrant that neither you nor any party having a direct or indirect beneficial interest in you or on whose behalf you are acting as agent or nominee is such a person or entity and you will comply with all applicable import, re-import, sanctions, anti-boycott, export, and re-export control laws and regulations. If this is not accurate or you do not agree, then you must immediately cease accessing our Material and delete all copies of Software. 13 | 14 | Any person using or offering Software in connection with providing software, goods or services to third parties shall advise such third parties of this important notice, including all limitations, restrictions and exclusions of liability. 15 | 16 | ## Trademarks 17 | Block.one, EOSIO, EOS, the heptahedron and associated logos and related marks are our trademarks. Other trademarks referenced in Material are the property of their respective owners. 18 | 19 | ## Third parties 20 | Any reference in Material to any third party or third-party product, resource or service is not an endorsement or recommendation by Block.one. We are not responsible for, and disclaim any and all responsibility and liability for, your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so information in Material may be out of date or inaccurate. 21 | 22 | ## Forward-looking statements 23 | Please note that in making statements expressing Block.one’s vision, we do not guarantee anything, and all aspects of our vision are subject to change at any time and in all respects at Block.one’s sole discretion, with or without notice. We call these “forward-looking statements”, which includes statements on our website and in other Material, other than statements of historical facts, such as statements regarding EOSIO’s development, expected performance, and future features, or our business strategy, plans, prospects, developments and objectives. These statements are only predictions and reflect Block.one’s current beliefs and expectations with respect to future events; they are based on assumptions and are subject to risk, uncertainties and change at any time. 24 | 25 | We operate in a rapidly changing environment and new risks emerge from time to time. Given these risks and uncertainties, you are cautioned not to rely on these forward-looking statements. Actual results, performance or events may differ materially from what is predicted in the forward-looking statements. Some of the factors that could cause actual results, performance or events to differ materially from the forward-looking statements include, without limitation: technical feasibility and barriers; market trends and volatility; continued availability of capital, financing and personnel; product acceptance; the commercial success of any new products or technologies; competition; government regulation and laws; and general economic, market or business conditions. 26 | 27 | All statements are valid only as of the date of first posting and Block.one is under no obligation to, and expressly disclaims any obligation to, update or alter any statements, whether as a result of new information, subsequent events or otherwise. Nothing in any Material constitutes technological, financial, investment, legal or other advice, either in general or with regard to any particular situation or implementation. Please consult with experts in appropriate areas before implementing or utilizing anything contained in Material. 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2020 block.one and its contributors. All rights reserved. 2 | 3 | The MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eosjs 2 | [![Build Status](https://github.com/eosio/eosjs/workflows/CI/badge.svg?branch=master)](https://github.com/EOSIO/eosjs/actions) [![npm version](https://badge.fury.io/js/eosjs.svg)](https://badge.fury.io/js/eosjs) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![npm](https://img.shields.io/npm/dw/eosjs.svg) 3 | 4 | Javascript API for integration with EOSIO-based blockchains using [EOSIO RPC API](https://developers.eos.io/eosio-nodeos/reference). 5 | 6 | Documentation can be found [here](https://eosio.github.io/eosjs) 7 | 8 | ## Installation 9 | 10 | ### NPM 11 | 12 | The official distribution package can be found at [npm](https://www.npmjs.com/package/eosjs). 13 | 14 | ### Add dependency to your project 15 | 16 | `yarn add eosjs` 17 | 18 | ### Using with Typescript 19 | 20 | In order to get access to the `TextEncoding` and `TextDecoding` types, you need to add `@types/text-encoding` as a dev dependency: 21 | `yarn add --dev @types/text-encoding` 22 | 23 | If you're using Node (not a browser) then you'll also need to make sure the `dom` lib is referenced in your `tsconfig.json`: 24 | 25 | ``` 26 | { 27 | "compilerOptions": { 28 | "lib": [..., "dom"] 29 | } 30 | } 31 | ``` 32 | 33 | ### Browser Distribution 34 | 35 | Clone this repository locally then run `yarn build-web`. The browser distribution will be located in `dist-web` and can be directly copied into your project repository. The `dist-web` folder contains minified bundles ready for production, along with source mapped versions of the library for debugging. For full browser usage examples, [see the documentation](https://eosio.github.io/eosjs/guides/1.-Browsers.html). 36 | 37 | ## Import 38 | 39 | ### ES Modules 40 | 41 | Importing using ESM syntax is supported using TypeScript, [webpack](https://webpack.js.org/api/module-methods), or [Node.js with `--experimental-modules` flag](https://nodejs.org/api/esm.html) 42 | ```js 43 | import { Api, JsonRpc, RpcError } from 'eosjs'; 44 | import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'; // development only 45 | ``` 46 | 47 | ### CommonJS 48 | 49 | Importing using commonJS syntax is supported by Node.js out of the box. 50 | ```js 51 | const { Api, JsonRpc, RpcError } = require('eosjs'); 52 | const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig'); // development only 53 | const fetch = require('node-fetch'); // node only; not needed in browsers 54 | const { TextEncoder, TextDecoder } = require('util'); // node only; native TextEncoder/Decoder 55 | ``` 56 | 57 | ## Basic Usage 58 | 59 | ### Signature Provider 60 | 61 | The Signature Provider holds private keys and is responsible for signing transactions. 62 | 63 | ***Using the JsSignatureProvider in the browser is not secure and should only be used for development purposes. Use a secure vault outside of the context of the webpage to ensure security when signing transactions in production*** 64 | 65 | ```js 66 | const defaultPrivateKey = "5JtUScZK2XEp3g9gh7F8bwtPTRAkASmNrrftmx4AxDKD5K4zDnr"; // bob 67 | const signatureProvider = new JsSignatureProvider([defaultPrivateKey]); 68 | ``` 69 | 70 | ### JSON-RPC 71 | 72 | Open a connection to JSON-RPC, include `fetch` when on Node.js. 73 | ```js 74 | const rpc = new JsonRpc('http://127.0.0.1:8888', { fetch }); 75 | ``` 76 | 77 | ### API 78 | 79 | Include textDecoder and textEncoder when using in Node. You may exclude these when running in a browser since most modern browsers now natively support these. If your browser does not support these (https://caniuse.com/#feat=textencoder), then you can import them as a dependency through the following deprecated npm package: https://www.npmjs.com/package/text-encoding 80 | ```js 81 | const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() }); 82 | ``` 83 | 84 | ### Sending a transaction 85 | 86 | `transact()` is used to sign and push transactions onto the blockchain with an optional configuration object parameter. This parameter can override the default value of `broadcast: true`, and can be used to fill TAPOS fields given `expireSeconds` and either `blocksBehind` or `useLastIrreversible`. Given no configuration options, transactions are expected to be unpacked with TAPOS fields (`expiration`, `ref_block_num`, `ref_block_prefix`) and will automatically be broadcast onto the chain. 87 | 88 | ```js 89 | (async () => { 90 | const result = await api.transact({ 91 | actions: [{ 92 | account: 'eosio.token', 93 | name: 'transfer', 94 | authorization: [{ 95 | actor: 'useraaaaaaaa', 96 | permission: 'active', 97 | }], 98 | data: { 99 | from: 'useraaaaaaaa', 100 | to: 'useraaaaaaab', 101 | quantity: '0.0001 SYS', 102 | memo: '', 103 | }, 104 | }] 105 | }, { 106 | blocksBehind: 3, 107 | expireSeconds: 30, 108 | }); 109 | console.dir(result); 110 | })(); 111 | ``` 112 | 113 | ### Error handling 114 | 115 | use `RpcError` for handling RPC Errors 116 | ```js 117 | ... 118 | try { 119 | const result = await api.transact({ 120 | ... 121 | } catch (e) { 122 | console.log('\nCaught exception: ' + e); 123 | if (e instanceof RpcError) 124 | console.log(JSON.stringify(e.json, null, 2)); 125 | } 126 | ... 127 | ``` 128 | 129 | ## Contributing 130 | 131 | [Contributing Guide](./CONTRIBUTING.md) 132 | 133 | [Code of Conduct](./CONTRIBUTING.md#conduct) 134 | 135 | ## License 136 | 137 | [MIT](./LICENSE) 138 | 139 | ## Important 140 | 141 | See [LICENSE](./LICENSE) for copyright and license terms. 142 | 143 | All repositories and other materials are provided subject to the terms of this [IMPORTANT](./IMPORTANT.md) notice and you must familiarize yourself with its terms. The notice contains important information, limitations and restrictions relating to our software, publications, trademarks, third-party resources, and forward-looking statements. By accessing any of our repositories and other materials, you accept and agree to the terms of the notice. 144 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "video": true, 3 | "fixturesFolder": false, 4 | "pluginsFile": false, 5 | "supportFile": false, 6 | "userAgent": "Chrome cypress" 7 | } 8 | -------------------------------------------------------------------------------- /cypress/integration/index.spec.js: -------------------------------------------------------------------------------- 1 | import { skipOn } from '@cypress/skip-test'; 2 | 3 | describe('eosjs web test', () => { 4 | it('loads', () => { 5 | cy.visit(('./src/tests/web.html')); 6 | }); 7 | 8 | it('test Transact With Config Blocks Behind', () => { 9 | cy.visit(('./src/tests/web.html')); 10 | cy.wait(500); 11 | cy.get('#testTransactWithConfigBlocksBehind').click(); 12 | cy.get('#testTransactWithConfigBlocksBehind').contains('Success', { timeout: 5000 }); 13 | }); 14 | 15 | it('test Transact With Config Use Last Irreversible', () => { 16 | cy.visit(('./src/tests/web.html')); 17 | cy.wait(500); 18 | cy.get('#testTransactWithConfigUseLastIrreversible').click(); 19 | cy.get('#testTransactWithConfigUseLastIrreversible').contains('Success', { timeout: 5000 }); 20 | }); 21 | 22 | it('test Transact Without Config', () => { 23 | if (Cypress.env('NODEOS_VER')) skipOn(Cypress.env('NODEOS_VER') === 'release/2.0.x'); 24 | cy.visit(('./src/tests/web.html')); 25 | cy.wait(500); 26 | cy.get('#testTransactWithoutConfig').click(); 27 | cy.get('#testTransactWithoutConfig').contains('Success', { timeout: 5000 }); 28 | }); 29 | 30 | it('test Transact With Compression', () => { 31 | cy.visit(('./src/tests/web.html')); 32 | cy.wait(500); 33 | cy.get('#testTransactWithCompression').click(); 34 | cy.get('#testTransactWithCompression').contains('Success', { timeout: 5000 }); 35 | }); 36 | 37 | it('test Transact With Context Free Action', () => { 38 | cy.visit(('./src/tests/web.html')); 39 | cy.wait(500); 40 | cy.get('#testTransactWithContextFreeAction').click(); 41 | cy.get('#testTransactWithContextFreeAction').contains('Success', { timeout: 5000 }); 42 | }); 43 | 44 | it('test Transact With Context Free Data', () => { 45 | cy.visit(('./src/tests/web.html')); 46 | cy.wait(500); 47 | cy.get('#testTransactWithContextFreeData').click(); 48 | cy.get('#testTransactWithContextFreeData').contains('Success', { timeout: 5000 }); 49 | }); 50 | 51 | it('test Transact Without Broadcast', () => { 52 | cy.visit(('./src/tests/web.html')); 53 | cy.wait(500); 54 | cy.get('#testTransactWithoutBroadcast').click(); 55 | cy.get('#testTransactWithoutBroadcast').contains('Success', { timeout: 5000 }); 56 | }); 57 | 58 | it('test Broadcast Result', () => { 59 | cy.visit(('./src/tests/web.html')); 60 | cy.wait(500); 61 | cy.get('#testBroadcastResult').click(); 62 | cy.get('#testBroadcastResult').contains('Success', { timeout: 5000 }); 63 | }); 64 | 65 | it('test Shorthand With Api Json', () => { 66 | cy.visit(('./src/tests/web.html')); 67 | cy.wait(500); 68 | cy.get('#testShorthandWithApiJson').click(); 69 | cy.get('#testShorthandWithApiJson').contains('Success', { timeout: 5000 }); 70 | }); 71 | 72 | it('test Shorthand With Tx Json', () => { 73 | cy.visit(('./src/tests/web.html')); 74 | cy.wait(500); 75 | cy.get('#testShorthandWithTxJson').click(); 76 | cy.get('#testShorthandWithTxJson').contains('Success', { timeout: 5000 }); 77 | }); 78 | 79 | it('test Shorthand With Tx Json Context Free Action', () => { 80 | cy.visit(('./src/tests/web.html')); 81 | cy.wait(500); 82 | cy.get('#testShorthandWithTxJsonContextFreeAction').click(); 83 | cy.get('#testShorthandWithTxJsonContextFreeAction').contains('Success', { timeout: 5000 }); 84 | }); 85 | 86 | it('test Shorthand With Tx Json Context Free Data', () => { 87 | cy.visit(('./src/tests/web.html')); 88 | cy.wait(500); 89 | cy.get('#testShorthandWithTxJsonContextFreeData').click(); 90 | cy.get('#testShorthandWithTxJsonContextFreeData').contains('Success', { timeout: 5000 }); 91 | }); 92 | 93 | it('test With P256 Elliptic Curve', () => { 94 | cy.visit(('./src/tests/web.html')); 95 | cy.wait(500); 96 | cy.get('#testWithP256EllipticCurve').click(); 97 | cy.get('#testWithP256EllipticCurve').contains('Success', { timeout: 5000 }); 98 | }); 99 | 100 | it('test With Return Value Tx', () => { 101 | if (Cypress.env('NODEOS_VER')) skipOn(Cypress.env('NODEOS_VER') === 'release/2.0.x'); 102 | cy.visit(('./src/tests/web.html')); 103 | cy.wait(500); 104 | cy.get('#testWithReturnValueTx').click(); 105 | cy.get('#testWithReturnValueTx').contains('Success', { timeout: 5000 }); 106 | }); 107 | 108 | it('test With Resource Payer Tx', () => { 109 | if (Cypress.env('NODEOS_VER')) skipOn(Cypress.env('NODEOS_VER') === 'release/2.0.x' || Cypress.env('NODEOS_VER') === 'release/2.1.x'); 110 | cy.visit(('./src/tests/web.html')); 111 | cy.wait(500); 112 | cy.get('#testWithResourcePayerTx').click(); 113 | cy.get('#testWithResourcePayerTx').contains('Success', { timeout: 5000 }); 114 | }); 115 | 116 | it('test With Read Only Query', () => { 117 | if (Cypress.env('NODEOS_VER')) skipOn(Cypress.env('NODEOS_VER') === 'release/2.0.x' || Cypress.env('NODEOS_VER') === 'release/2.1.x'); 118 | cy.visit(('./src/tests/web.html')); 119 | cy.wait(500); 120 | cy.get('#testWithReadOnlyQuery').click(); 121 | cy.get('#testWithReadOnlyQuery').contains('Success', { timeout: 5000 }); 122 | }); 123 | 124 | it('test With Read Only Failure Trace', () => { 125 | if (Cypress.env('NODEOS_VER')) skipOn(Cypress.env('NODEOS_VER') === 'release/2.0.x' || Cypress.env('NODEOS_VER') === 'release/2.1.x'); 126 | cy.visit(('./src/tests/web.html')); 127 | cy.wait(500); 128 | cy.get('#testWithReadOnlyFailureTrace').click(); 129 | cy.get('#testWithReadOnlyFailureTrace').contains('Success', { timeout: 5000 }); 130 | }); 131 | 132 | it('test Transact Should Fail', () => { 133 | cy.visit(('./src/tests/web.html')); 134 | cy.wait(500); 135 | cy.get('#testTransactShouldFail').click(); 136 | cy.get('#testTransactShouldFail').contains('Success', { timeout: 5000 }); 137 | }); 138 | 139 | it('test Rpc Should Fail', () => { 140 | cy.visit(('./src/tests/web.html')); 141 | cy.wait(500); 142 | cy.get('#testRpcShouldFail').click(); 143 | cy.get('#testRpcShouldFail').contains('Success', { timeout: 5000 }); 144 | }); 145 | }); 146 | -------------------------------------------------------------------------------- /docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eosjs", 3 | "generators": [ 4 | { 5 | "name": "collate_markdown", 6 | "options": { 7 | "docs_dir": "docs" 8 | } 9 | }, 10 | { 11 | "name": "typedoc", 12 | "options": { 13 | "disable_default_filters": true, 14 | "filters": [ 15 | { "name": "remove_extension" } 16 | ] 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /docs/01_technical-overview.md: -------------------------------------------------------------------------------- 1 | As stated in the [introduction](index.md), `eosjs` integrates with EOSIO-based blockchains using the [EOSIO Nodeos RPC API](https://developers.eos.io/eosio-nodeos/reference). 2 | 3 | In general, there are two objects that are used to interact with a blockchain via `eosjs`: the `JsonRpc` object, and the `Api` object. 4 | 5 | ## JsonRpc 6 | The `JsonRpc` object is typically used when signing is not necessary. Some examples include [getting block information](how-to-guides/00_how-to-get-block-information.md), [getting transaction information](how-to-guides/02_how-to-get-transaction-information.md), or [getting table information](how-to-guides/09_how-to-get-table-information.md). 7 | 8 | The requests made by the `JsonRpc` object will either use a built-in `fetch` library, or [the `fetch` library passed in by the user](basic-usage/01_commonjs.md) to issue requests to the endpoint specified when instantiating the `JsonRpc` object. When the various methods ([get_abi](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L66), [get_account](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L71), [get_block_header_state](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L76), etc) of the `JsonRpc` object are invoked, the calls are delegated to the `JsonRpc` object's [fetch function](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L42-L63), which in turn, delegate the requests to the `fetch` library. 9 | 10 | ## Api 11 | The `Api` object is typically used when transacting on an EOSIO-based blockchain. Some examples include [staking](how-to-guides/03_how-to-stake.md), [creating an account](how-to-guides/05_how-to-create-an-account.md), or [proposing multi-sig transactions](how-to-guides/13_how-to-propose-a-multisig-transaction.md). 12 | 13 | The typical use of the `Api` object is to call its [`transact` method](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-api.ts#L214-L254). This method performs a number of steps depending on the input passed to it: 14 | 15 | * The `transact` method first checks if the **chainId** was set in the `Api` constructor, and if not, uses the [`JsonRpc` object's](#jsonrpc) [`get_info`](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L101) method to retrieve the **chainId**. 16 | * The `transact` method then checks if the `expireSeconds` and either `blocksBehind` or `useLastIrreversible` fields are set and well-formed in the [optional configuration object, as specified in *How to Submit a Transaction*](how-to-guides/01_how-to-submit-a-transaction.md#). 17 | * If so, either the *last_irreversible_block_num* or the block *blocksBehind* the head block retrieved from [`JsonRpc`'s `get_info`](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L101) is set as the reference block and the transaction header is serialized using this reference block and the `expireSeconds` field. 18 | * The `transact` method then checks if the appropriate TAPOS fields are present in the transaction ([they can either be specified directly in the transaction or in the optional configuration object](how-to-guides/01_how-to-submit-a-transaction.md#)) and throws an Error if not. 19 | * The necessary `abi`s for a transaction are then retrieved for the case when `transact` is expected to sign the transaction. 20 | * The `actions` are serialized using the `eosjs-serialize` `ser` object. 21 | * The entire transaction is then [serialized](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-api.ts#L154-L166), also using the `eosjs-serialize` `ser` object. 22 | * The transaction is then optionally signed, using the `signatureProvider`, the previously retrieved `abi`s, the private keys of the `signatureProvider`, and the `chainId`. 23 | * The transaction is then optionally compressed, using the `deflate` function of a Javascript zlib library. 24 | * The transaction is then optionally broadcasted using `JsonRpc`'s [`push_transaction`](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-jsonrpc.ts#L187). -------------------------------------------------------------------------------- /docs/02_installation.md: -------------------------------------------------------------------------------- 1 | `eosjs` can be installed via [`yarn`](https://yarnpkg.com/en/) 2 | ```javascript 3 | yarn add eosjs 4 | ``` 5 | 6 | or [`npm`](https://www.npmjs.com/) 7 | ```javascript 8 | npm install eosjs 9 | ``` -------------------------------------------------------------------------------- /docs/basic-usage/00_browser.md: -------------------------------------------------------------------------------- 1 | To use `eosjs` in a browser run `npm run build-web` or `yarn build-web`. This will create the `dist-web` folder and web distribution modules. Ensure that you include `externals.min.js` as it includes external packages that eosjs uses. 2 | ```html 3 |

 4 | 
 5 | 
 6 | 
 7 | 
 8 | 
 9 | ```
10 | 
11 | To cache ABIs and reduce network usage, reuse the `api` object for all transactions.  This implies you should only call `new eosjs_api.Api(...)` once.
12 | ```html
13 | 
49 | ```
50 | 
51 | ## Debugging
52 | If you would like readable source files for debugging, change the file reference to the `.js` files inside `dist-web` directory.  These files should only be used for development as they are over 10 times as large as the minified versions, and importing the debug versions will increase loading times for the end user.
53 | 
54 | ## IE11 and Edge Support
55 | If you need to support IE11 or Edge you will also need to install a text-encoding polyfill, as eosjs Signing is dependent on the TextEncoder which IE11 and Edge do not provide.  Pass the TextEncoder and TextDecoder to the API constructor as demonstrated in the [CommonJS example](01_commonjs.md).  Refer to the documentation [here](https://github.com/inexorabletash/text-encoding) to determine the best way to include it in your project.


--------------------------------------------------------------------------------
/docs/basic-usage/01_commonjs.md:
--------------------------------------------------------------------------------
 1 | To import `eosjs` using commonjs syntax follow the code below.
 2 | ```javascript
 3 | const { Api, JsonRpc } = require('eosjs');
 4 | const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig');  // development only
 5 | const fetch = require('node-fetch'); //node only
 6 | const { TextDecoder, TextEncoder } = require('util'); //node only
 7 | 
 8 | const privateKeys = [privateKey1];
 9 | 
10 | const signatureProvider = new JsSignatureProvider(privateKeys);
11 | const rpc = new JsonRpc('http://127.0.0.1:8888', { fetch }); //required to read blockchain state
12 | const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() }); //required to submit transactions
13 | ```


--------------------------------------------------------------------------------
/docs/basic-usage/02_es-modules.md:
--------------------------------------------------------------------------------
 1 | To import `eosjs` using [ES module syntax](https://en.wikipedia.org/wiki/ECMAScript) the following code is provided.
 2 | ```javascript
 3 | import { Api, JsonRpc } from 'eosjs';
 4 | import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig';  // development only
 5 | 
 6 | const privateKeys = [privateKey1];
 7 | 
 8 | const signatureProvider = new JsSignatureProvider(privateKeys);
 9 | const rpc = new JsonRpc('http://127.0.0.1:8888'); //required to read blockchain state
10 | const api = new Api({ rpc, signatureProvider }); //required to submit transactions
11 | ```


--------------------------------------------------------------------------------
/docs/basic-usage/index.md:
--------------------------------------------------------------------------------
 1 | The `eosjs` package provides two objects: an `Api` object and a `JsonRpc` object.  An explanation of their expected parameters and usage is provided below.
 2 | 
 3 | ## JsonRpc
 4 | The `JsonRpc` object takes the node you wish to connect to in the form of a string as a required constructor argument, as well as an optional `fetch` object (see [CommonJS](01_commonjs.md) for an example).  
 5 | 
 6 | Note that reading blockchain state requires only an instance of `JsonRpc` connected to a node and not the `Api` object.
 7 | 
 8 | ## Api
 9 | To send transactions and trigger actions on the blockchain, you must have an instance of `Api`. This `Api` instance is required to receive a SignatureProvider object in it's constructor.
10 | 
11 | The SignatureProvider object must contain the private keys corresponding to the actors and permission requirements of the actions being executed.
12 | 
13 | ## JsSignatureProvider
14 | The Api constructor requires a SignatureProvider. SignatureProviders implement the `dist/eosjs-api-interfaces.SignatureProvider` interface. For development purpose only, a `JsSignatureProvider` object is also provided via the `dist/eosjs-jssig` import to stand-in for an easy option for a signature provider during development, but should only be used in development, as it is not secure.
15 | 
16 | In production code, it is recommended that you use a secure vault outside of the context of the webpage (which will also implement the `eosjs-api-interfaces.SignatureProvider` interface) to ensure security when signing transactions.
17 | 


--------------------------------------------------------------------------------
/docs/faq/00_what-is-a-signature-provider.md:
--------------------------------------------------------------------------------
1 | `eosjs` provides an example implementation of the [`SignatureProvider` interface](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-api-interfaces.ts#L60) called [`JsSignatureProvider`](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-jssig.ts#L11).
2 | 
3 | Although `JsSignatureProvider` is insecure and should not be used in production, it provides a basic example of what a `SignatureProvider` is and does.  `JsSignatureProvider` simply takes a list of private keys as strings in its constructor and maps these private keys to their respective public keys.  When [`JsSignatureProvider`'s `sign`](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-jssig.ts#L33) is called, a buffer of the `chainId` and `serializedTransaction` is created and [`eosjs-ecc`'s `ecc` object](https://github.com/EOSIO/eosjs-ecc/blob/7ec577cad54e17da6168fdfb11ec2b09d6f0e7f0/src/index.js#L4) is used to sign the buffer with the private key corresponding to the required public key.


--------------------------------------------------------------------------------
/docs/faq/01_example-signature-providers.md:
--------------------------------------------------------------------------------
1 | Since it is not recommended that you use `JsSignatureProvider`, a list of `SignatureProvider`s is provided below, along with a link to the documentation:
2 | 
3 | * [Ledger Signature Provider](https://github.com/EOSIO/eosjs-ledger-signature-provider)


--------------------------------------------------------------------------------
/docs/how-to-guides/00_how-to-get-block-information.md:
--------------------------------------------------------------------------------
 1 | To get block information call `get_block` on the rpc object passing in the block number as a required argument.
 2 | ```javascript
 3 | (async () => { 
 4 |   await rpc.get_block(1) //get the first block
 5 | })();
 6 | ```
 7 | 
 8 | The block data is returned as JSON.
 9 | ```json
10 | { 
11 |   "timestamp": "2018-06-01T12:00:00.000",
12 |   "producer": "",
13 |   "confirmed": 1,
14 |   "previous": "0000000000000000000000000000000000000000000000000000000000000000",
15 |   "transaction_mroot": "0000000000000000000000000000000000000000000000000000000000000000",
16 |   "action_mroot": "cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f",
17 |   "schedule_version": 0,
18 |   "new_producers": null,
19 |   "header_extensions": [],
20 |   "producer_signature": "SIG_K1_111111111111111111111111111111111111111111111111111111111111111116uk5ne",
21 |   "transactions": [],
22 |   "block_extensions": [],
23 |   "id": "00000001bcf2f448225d099685f14da76803028926af04d2607eafcf609c265c",
24 |   "block_num": 1,
25 |   "ref_block_prefix": 2517196066 
26 | }
27 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/01_how-to-submit-a-transaction.md:
--------------------------------------------------------------------------------
  1 | To submit a transaction, call `transact` on the api object, passing in two parameters.
  2 | 
  3 | The first parameter specifies the actions in the transaction, and their corresponding authorizations, as well as any data necessary for the action to execute.  An example for the [`buyrambytes` action](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L1028) is shown below.
  4 | ```javascript
  5 | { 
  6 |    actions: [{
  7 |      account: 'eosio',
  8 |      name: 'buyrambytes',
  9 |      authorization: [{
 10 |        actor: 'useraaaaaaaa',
 11 |        permission: 'active',
 12 |      }],
 13 |      data: {
 14 |        payer: 'useraaaaaaaa',
 15 |        receiver: 'useraaaaaaaa',
 16 |        bytes: 8192,
 17 |      },
 18 |    }]
 19 | }
 20 | ```
 21 | The second parameter is an [optional configuration object parameter](https://github.com/EOSIO/eosjs/blob/master/src/eosjs-api.ts#L215).  This optional parameter can override the default values of `broadcast: true` and `sign: true`, and can be used to fill [TAPOS](https://eosio.stackexchange.com/questions/2362/what-is-transaction-as-proof-of-stake-tapos-and-when-would-a-smart-contract) fields with the specified `expireSeconds` and either `blocksBehind` or `useLastIrreversible` if necessary.  A combination of these fields are required if the first parameter specified above does not itself contain the TAPOS fields `expiration`, `ref_block_num`, and `ref_block_prefix`.  In this case it does not, so the fields are necessary.
 22 | ```javascript
 23 | {
 24 |   blocksBehind: 3,
 25 |   expireSeconds: 30,
 26 | }
 27 | ```
 28 | Below is a complete example transaction to call the `buyrambytes` action with `useraaaaaaaa`'s active permission, `useraaaaaaaa` is also both the payer and receiver of **8192** bytes of RAM.  
 29 | The transaction will reference the block 3 blocks behind the head block, and will automatically expire the transaction 30 seconds after the time present in this referenced block.
 30 | ```javascript
 31 | (async () => {
 32 |   const transaction = await api.transact({
 33 |    actions: [{
 34 |      account: 'eosio',
 35 |      name: 'buyrambytes',
 36 |      authorization: [{
 37 |        actor: 'useraaaaaaaa',
 38 |        permission: 'active',
 39 |      }],
 40 |      data: {
 41 |        payer: 'useraaaaaaaa',
 42 |        receiver: 'useraaaaaaaa',
 43 |        bytes: 8192,
 44 |      },
 45 |    }]
 46 |   }, {
 47 |    blocksBehind: 3,
 48 |    expireSeconds: 30,
 49 |   });
 50 | })();
 51 | ```
 52 | 
 53 | Alternatively, the transaction could be submitted without the optional configuration object by specifying the TAPOS fields `expiration`, `ref_block_num`, and `ref_block_prefix` explicity in the action.
 54 | ```javascript
 55 | (async () => {
 56 |   const transaction = await api.transact({
 57 |    expiration: '2019-09-19T16:39:15',
 58 |    ref_block_num: '50477227',
 59 |    ref_block_prefix: '1022379673',
 60 |    actions: [{
 61 |      account: 'eosio',
 62 |      name: 'buyrambytes',
 63 |      authorization: [{
 64 |        actor: 'useraaaaaaaa',
 65 |        permission: 'active',
 66 |      }],
 67 |      data: {
 68 |        payer: 'useraaaaaaaa',
 69 |        receiver: 'useraaaaaaaa',
 70 |        bytes: 8192,
 71 |      },
 72 |    }]
 73 |   });
 74 | })();
 75 | ```
 76 | 
 77 | #### Concise Actions
 78 | To construct transactions and actions in a more concise way, you can also utilize this format instead:
 79 | ```javascript
 80 | (async () => {
 81 |   await api.transact({ 
 82 |    actions: [
 83 |      api.with('eosio').as('useraaaaaaaa').buyrambytes('useraaaaaaaa', 'useraaaaaaaa', 8192)
 84 |    ]
 85 |   }, {
 86 |     blocksBehind: 3,
 87 |     expireSeconds: 30,
 88 |   });
 89 | })();
 90 | ```
 91 | With this concise format of an action, the `with()` function has the account, `as()` contains the actor, and the name of the action is the third function.  The arguments within the action function are listed in the same order as the arguments from the smart contract.  You can also send a longer authentication within the `as()` function, such as `[{ actor: ‘useraaaaaaaa’, permission: ‘active’}]`.
 92 | 
 93 | Before using this structure, you need to cache the JSON Abi:
 94 | ```javascript
 95 | (async () => {
 96 |   await api.getAbi('eosio');
 97 |   ...
 98 | })();
 99 | ```
100 | 
101 | Additionally, utilizing this structure, a stateful transaction object can be created and passed through your application before sending when ready.  The transaction object can also be created as a callback method.
102 | 
103 | ```javascript
104 | (async () => {
105 |   const tx = api.buildTransaction();
106 |   tx.with('eosio').as('useraaaaaaaa').buyrambytes('useraaaaaaaa', 'useraaaaaaaa', 8192)
107 |   await tx.send({ blocksBehind: 3, expireSeconds: 30 });
108 | 
109 |   // ...or...
110 | 
111 |   api.buildTransaction(async (tx) => {
112 |     tx.with('eosio').as('useraaaaaaaa').buyrambytes('useraaaaaaaa', 'useraaaaaaaa', 8192)
113 |     await tx.send({ blocksBehind: 3, expireSeconds: 30 });
114 |   });
115 | })();
116 | ```
117 | 
118 | By using this object and passing it around your application, it might be more difficult for your application to keep the correct references and indexes for context free actions. The transaction object has a function for mapping actions, context free actions, and context free data together.
119 | 
120 | ```javascript
121 | (async () => {
122 |   const tx = api.buildTransaction();
123 |   tx.associateContextFree((index) => ({
124 |     contextFreeData: cfdata,
125 |     contextFreeAction: tx.with('account').as().cfaName(index.cfd, 'context free example'),
126 |     action: tx.with('account').as('actor').actionName('example', index.cfa)
127 |   }));
128 |   await tx.send({ blocksBehind: 3, expireSeconds: 30 });
129 | })();
130 | ```
131 | 
132 | By providing that function inside `tx.associateContextFree()`, the transaction object will provide the correct indexes for the context free action and context free data.  You can input the `index.cfa` or `index.cfd` arguments where your smart contract requires that index in the list of arguments.  Additionally, all three object keys are not necessary in the function, in case for example, the action is not necessary for your context free action.
133 | 
134 | #### Return Values
135 | From nodeos version 2.1, the ability to receive return values from smart contracts to eosjs has been introduced.  In the above examples, the `transaction` object will include the values `transaction_id` and the `processed` object.  If your smart contract returns values, you will be able to find the values within the `transaction.processed.action_traces` array.  The order of the `action_traces` array matches the order of actions in your transaction and within those `action_trace` objects, you can find your deserialized return value for your action in the `return_value` field.
136 | 
137 | ### Read-Only Transactions
138 | From nodeos version 2.2, read-only queries have been introduced to eosjs. Adding `readOnlyTrx` to the `transact` config will send the transaction through the `push_ro_transaction` endpoint in the `chain_api`.  The `push_ro_transaction` endpoint does not allow the transaction to make any data changes despite the actions in the transaction. The `push_ro_transaction` endpoint may also be used to call normal actions, but any data changes that action will make will be rolled back.
139 | 
140 | Adding returnFailureTraces to the transact config enables the return of a trace message if your transaction fails. At this time, this is only available for the `push_ro_transaction` endpoint.
141 | 


--------------------------------------------------------------------------------
/docs/how-to-guides/02_how-to-get-transaction-information.md:
--------------------------------------------------------------------------------
 1 | **Note** that [`history_get_transaction`](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-jsonrpc.ts#L205) below uses the deprecated `/v1/history/get_transaction` endpoint of a node.
 2 | 
 3 | To get a transaction's information, call [`history_get_transaction`](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-jsonrpc.ts#L205) on the rpc object passing in the transaction's id and optionally, it's block number as arguments.
 4 | ```javascript
 5 | (async () => {
 6 |   await rpc.history_get_transaction('b3598da4e007173e6d1b94d7be306299dd0a6813d114cf9a08c8e88a5756f1eb', 46632826)
 7 | })();
 8 | ```
 9 | 
10 | The transaction info is returned as JSON.
11 | ```javascript
12 | {
13 |   id: 'b3598da4e007173e6d1b94d7be306299dd0a6813d114cf9a08c8e88a5756f1eb',
14 |   trx: {
15 |     receipt: {
16 |       status: 'executed',
17 |       cpu_usage_us: 2070,
18 |       net_usage_words: 14,
19 |       trx: [Array]
20 |     },
21 |     trx: {
22 |       expiration: '2019-08-28T03:45:47',
23 |       ref_block_num: 36720,
24 |       ref_block_prefix: 654845510,
25 |       max_net_usage_words: 0,
26 |       max_cpu_usage_ms: 0,
27 |       delay_sec: 0,
28 |       context_free_actions: [],
29 |       actions: [Array],
30 |       transaction_extensions: [],
31 |       signatures: [Array],
32 |       context_free_data: []
33 |     }
34 |   },
35 |   block_time: '2019-08-28T03:45:21.500',
36 |   block_num: 46632826,
37 |   last_irreversible_block: 46784285,
38 |   traces: []
39 | }
40 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/03_how-to-stake.md:
--------------------------------------------------------------------------------
 1 | To stake resources, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`delegatebw`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L692) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` stakes **1.0000 SYS** of NET and CPU to the account `mynewaccount`.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio',
 9 |       name: 'delegatebw',
10 |       authorization: [{
11 |         actor: 'useraaaaaaaa',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         from: 'useraaaaaaaa',
16 |         receiver: 'mynewaccount',
17 |         stake_net_quantity: '1.0000 SYS',
18 |         stake_cpu_quantity: '1.0000 SYS',
19 |         transfer: false,
20 |       }
21 |     }]
22 |   }, {
23 |     blocksBehind: 3,
24 |     expireSeconds: 30,
25 |   });
26 | })();
27 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/04_how-to-unstake.md:
--------------------------------------------------------------------------------
 1 | To unstake resources, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`undelegatebw`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L1000) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` unstakes **1.0000 SYS** of NET and CPU from the account `mynewaccount`.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio',
 9 |       name: 'undelegatebw',
10 |       authorization: [{
11 |         actor: 'useraaaaaaaa',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         from: 'useraaaaaaaa',
16 |         receiver: 'mynewaccount',
17 |         stake_net_quantity: '1.0000 SYS',
18 |         stake_cpu_quantity: '1.0000 SYS',
19 |         transfer: false,
20 |       }
21 |     }]
22 |   }, {
23 |     blocksBehind: 3,
24 |     expireSeconds: 30,
25 |   });
26 | })();
27 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/05_how-to-create-an-account.md:
--------------------------------------------------------------------------------
  1 | To create a new account submit three actions to the `eosio` account using the `actions` array as shown in [how-to-submit-a-transaction](01_how-to-submit-a-transaction.md).
  2 | 
  3 | ## newaccount
  4 | The first action is the [`newaccount`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/native.hpp#L178) action.  In the example shown below `useraaaaaaaa` creates new account `mynewaccount` with owner and active public key `PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu`.  Ideally, these should be different public keys.
  5 | 
  6 | ```javascript
  7 |   {
  8 |     account: 'eosio',
  9 |     name: 'newaccount',
 10 |     authorization: [{
 11 |       actor: 'useraaaaaaaa',
 12 |       permission: 'active',
 13 |     }],
 14 |     data: {
 15 |       creator: 'useraaaaaaaa',
 16 |       name: 'mynewaccount',
 17 |       owner: {
 18 |         threshold: 1,
 19 |         keys: [{
 20 |           key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu',
 21 |           weight: 1
 22 |         }],
 23 |         accounts: [],
 24 |         waits: []
 25 |       },
 26 |       active: {
 27 |         threshold: 1,
 28 |         keys: [{
 29 |           key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu',
 30 |           weight: 1
 31 |         }],
 32 |         accounts: [],
 33 |         waits: []
 34 |       },
 35 |     }
 36 |   }
 37 | ```
 38 | 
 39 | ## buyrambytes
 40 | The second action is the [`buyrambytes`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L1028) action.  In the example shown below `useraaaaaaaa` pays for **8192** bytes of RAM for the account `mynewaccount` created in the [first action](#newaccount).
 41 | 
 42 | ```javascript
 43 |   {
 44 |     account: 'eosio',
 45 |     name: 'buyrambytes',
 46 |     authorization: [{
 47 |       actor: 'useraaaaaaaa',
 48 |       permission: 'active',
 49 |     }],
 50 |     data: {
 51 |       payer: 'useraaaaaaaa',
 52 |       receiver: 'mynewaccount',
 53 |       bytes: 8192,
 54 |     },
 55 |   }
 56 | ```
 57 | 
 58 | ## delegatebw
 59 | The third action is the [`delegatebw`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L692) action.  In the example shown below `useraaaaaaaa` delegates **1.0000 SYS** of NET and CPU to the account `mynewaccount` created in the [first action](#newaccount).
 60 | ```javascript
 61 |   {
 62 |     account: 'eosio',
 63 |     name: 'delegatebw',
 64 |     authorization: [{
 65 |       actor: 'useraaaaaaaa',
 66 |       permission: 'active',
 67 |     }],
 68 |     data: {
 69 |       from: 'useraaaaaaaa',
 70 |       receiver: 'mynewaccount',
 71 |       stake_net_quantity: '1.0000 SYS',
 72 |       stake_cpu_quantity: '1.0000 SYS',
 73 |       transfer: false,
 74 |     }
 75 |   }
 76 | ```
 77 | 
 78 | ## Create An Account
 79 | Below the three actions are submitted as one transaction using the `Api` object.
 80 | 
 81 | ```javascript
 82 | (async () => {
 83 |   await api.transact({
 84 |     actions: [{
 85 |       account: 'eosio',
 86 |       name: 'newaccount',
 87 |       authorization: [{
 88 |         actor: 'useraaaaaaaa',
 89 |         permission: 'active',
 90 |       }],
 91 |       data: {
 92 |         creator: 'useraaaaaaaa',
 93 |         name: 'mynewaccount',
 94 |         owner: {
 95 |           threshold: 1,
 96 |           keys: [{
 97 |             key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu',
 98 |             weight: 1
 99 |           }],
100 |           accounts: [],
101 |           waits: []
102 |         },
103 |         active: {
104 |           threshold: 1,
105 |           keys: [{
106 |             key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu',
107 |             weight: 1
108 |           }],
109 |           accounts: [],
110 |           waits: []
111 |         },
112 |       },
113 |     },
114 |     {
115 |       account: 'eosio',
116 |       name: 'buyrambytes',
117 |       authorization: [{
118 |         actor: 'useraaaaaaaa',
119 |         permission: 'active',
120 |       }],
121 |       data: {
122 |         payer: 'useraaaaaaaa',
123 |         receiver: 'mynewaccount',
124 |         bytes: 8192,
125 |       },
126 |     },
127 |     {
128 |       account: 'eosio',
129 |       name: 'delegatebw',
130 |       authorization: [{
131 |         actor: 'useraaaaaaaa',
132 |         permission: 'active',
133 |       }],
134 |       data: {
135 |         from: 'useraaaaaaaa',
136 |         receiver: 'mynewaccount',
137 |         stake_net_quantity: '1.0000 SYS',
138 |         stake_cpu_quantity: '1.0000 SYS',
139 |         transfer: false,
140 |       }
141 |     }]
142 |   }, {
143 |     blocksBehind: 3,
144 |     expireSeconds: 30,
145 |   });
146 | })();
147 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/06_how-to-deploy-a-smart-contract.md:
--------------------------------------------------------------------------------
  1 | In order to deploy a smart contract using `eosjs`, call the [`setcode`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/native.hpp#L294) followed by the [`setabi`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/native.hpp#L281) actions of the `eosio` account.
  2 | 
  3 | ## setcode
  4 | `setcode` takes the name of the account where the smart contract will be deployed to and the smart contract **.wasm** file.  The smart contract **.wasm** file should be a hex string.  Assuming that a valid **.wasm** file is located at `/mypath/my_smart_contract.wasm`, converting a smart contract to a hex string can be accomplished using the code below.
  5 | ```javascript
  6 | const fs = require('fs')
  7 | const wasmFilePath = '/mypath/my_smart_contract.wasm'
  8 | const wasmHexString = fs.readFileSync(wasmFilePath).toString('hex')
  9 | ```
 10 | 
 11 | In the example shown below `useraaaaaaaa` sets the account `useraaaaaaaa`'s code to the smart contract located at `/mypath/my_smart_contract.wasm`'s hex string representation. 
 12 | ```javascript
 13 |         {
 14 |           account: 'eosio',
 15 |           name: 'setcode',
 16 |           authorization: [
 17 |             {
 18 |               actor: 'useraaaaaaaa',
 19 |               permission: 'active',
 20 |             },
 21 |           ],
 22 |           data: {
 23 |             account: 'useraaaaaaaa',
 24 |             code: wasmHexString,
 25 |           },
 26 |         }
 27 | ```
 28 | 
 29 | ## setabi
 30 | `setabi` takes the name of the account where the smart contract will be deployed to and the serialized **.abi** file corresponding to the **.wasm** used in the [`setcode`](#setcode) action corresponding to this `setabi` action.  The following code is provided to serialize **.abi** files.
 31 | 
 32 | ```javascript
 33 | const fs = require('fs')
 34 | 
 35 | const buffer = new Serialize.SerialBuffer({
 36 |     textEncoder: api.textEncoder,
 37 |     textDecoder: api.textDecoder,
 38 | })
 39 | 
 40 | const abiFilePath = '/mypath/my_smart_contract.abi'
 41 | let abiJSON = JSON.parse(fs.readFileSync(abiFilePath, 'utf8'))
 42 | const abiDefinitions = api.abiTypes.get('abi_def')
 43 | 
 44 | abiJSON = abiDefinitions.fields.reduce(
 45 |     (acc, { name: fieldName }) =>
 46 |         Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
 47 |         abiJSON
 48 |     )
 49 | abiDefinitions.serialize(buffer, abiJSON)
 50 | serializedAbiHexString = Buffer.from(buffer.asUint8Array()).toString('hex')
 51 | ```
 52 | Note that the `api` object from [initialization](../basic-usage/01_commonjs.md) is used for it's `textEncoder`and `textDecoder` objects, as well as it's [`abiTypes`](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-api.ts#L72) map.
 53 | 
 54 | This line in particular:
 55 | ```javascript
 56 | abiJSON = abiDefinitions.fields.reduce(
 57 |     (acc, { name: fieldName }) =>
 58 |         Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
 59 |         abiJSON
 60 |     )
 61 | ```
 62 | ensures that the **.abi** file contains [the fields that an **.abi** file is expected to contain](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/abi.abi.json#L151).  Note that if an expected field is missing, the call to `serialize` will [throw an exception](https://github.com/EOSIO/eosjs/blob/849c03992e6ce3cb4b6a11bf18ab17b62136e5c9/src/eosjs-serialize.ts#L644) indicating the missing field.
 63 | 
 64 | ## Deploying a Smart Contract
 65 | Below the two actions are submitted as one transaction using the `Api` object.
 66 | ```javascript
 67 | (async () => {
 68 |   await api.transact({
 69 |       actions: [
 70 |         {
 71 |           account: 'eosio',
 72 |           name: 'setcode',
 73 |           authorization: [
 74 |             {
 75 |               actor: 'useraaaaaaaa',
 76 |               permission: 'active',
 77 |             },
 78 |           ],
 79 |           data: {
 80 |             account: 'useraaaaaaaa',
 81 |             code: wasmHexString,
 82 |           },
 83 |         },
 84 |         {
 85 |           account: 'eosio',
 86 |           name: 'setabi',
 87 |           authorization: [
 88 |             {
 89 |               actor: 'useraaaaaaaa',
 90 |               permission: 'active',
 91 |             },
 92 |           ],
 93 |           data: {
 94 |             account: 'useraaaaaaaa',
 95 |             abi: serializedAbiHexString,
 96 |           },
 97 |         },
 98 |       ],
 99 |     },
100 |     {
101 |       blocksBehind: 3,
102 |       expireSeconds: 30,
103 |     });
104 | })();
105 | ```
106 | 
107 | The entire code is provided below for reference.
108 | ```javascript
109 | const wasmFilePath = '/mypath/my_smart_contract.wasm'
110 | const abiFilePath = '/mypath/my_smart_contract.abi'
111 | 
112 | const wasmHexString = fs.readFileSync(wasmFilePath).toString('hex')
113 | 
114 | const buffer = new Serialize.SerialBuffer({
115 |     textEncoder: api.textEncoder,
116 |     textDecoder: api.textDecoder,
117 | })
118 | 
119 | let abiJSON = JSON.parse(fs.readFileSync(abiFilePath, 'utf8'))
120 | const abiDefinitions = api.abiTypes.get('abi_def')
121 | abiJSON = abiDefinitions.fields.reduce(
122 |     (acc, { name: fieldName }) =>
123 |         Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
124 |         abiJSON
125 |     )
126 | abiDefinitions.serialize(buffer, abiJSON)
127 | serializedAbiHexString = Buffer.from(buffer.asUint8Array()).toString('hex')
128 | 
129 | await api.transact(
130 |     {
131 |       actions: [
132 |         {
133 |           account: 'eosio',
134 |           name: 'setcode',
135 |           authorization: [
136 |             {
137 |               actor: 'useraaaaaaaa',
138 |               permission: 'active',
139 |             },
140 |           ],
141 |           data: {
142 |             account: 'useraaaaaaaa',
143 |             code: wasmHexString,
144 |           },
145 |         },
146 |         {
147 |           account: 'eosio',
148 |           name: 'setabi',
149 |           authorization: [
150 |             {
151 |               actor: 'useraaaaaaaa',
152 |               permission: 'active',
153 |             },
154 |           ],
155 |           data: {
156 |             account: 'useraaaaaaaa',
157 |             abi: serializedAbiHexString,
158 |           },
159 |         },
160 |       ],
161 |     },
162 |     {
163 |       blocksBehind: 3,
164 |       expireSeconds: 30,
165 |     }
166 |   )
167 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/07_how-to-get-account-information.md:
--------------------------------------------------------------------------------
 1 | To get a specific account's information call `get_account` on the rpc object passing in the account name as a function argument.
 2 | ```javascript
 3 | (async () => {
 4 |   await rpc.get_account('alice') //get alice's account info.  This assumes the account 'alice' has been created on the chain specified in the rpc object.
 5 | })();
 6 | ```
 7 | 
 8 | The account info is returned as JSON.
 9 | ```json
10 | { "account_name": "testacc",
11 |   "head_block_num": 1079,
12 |   "head_block_time": "2018-11-10T00:45:53.500",
13 |   "privileged": false,
14 |   "last_code_update": "1970-01-01T00:00:00.000",
15 |   "created": "2018-11-10T00:37:05.000",
16 |   "ram_quota": -1,
17 |   "net_weight": -1,
18 |   "cpu_weight": -1,
19 |   "net_limit": { "used": -1, "available": -1, "max": -1 },
20 |   "cpu_limit": { "used": -1, "available": -1, "max": -1 },
21 |   "ram_usage": 2724,
22 |   "permissions":
23 |    [ { "perm_name": "active", "parent": "owner", "required_auth": [] },
24 |      { "perm_name": "owner", "parent": "", "required_auth": [] } ],
25 |   "total_resources": null,
26 |   "self_delegated_bandwidth": null,
27 |   "refund_request": null,
28 |   "voter_info": null }
29 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/08_how-to-transfer-an-eosio-token.md:
--------------------------------------------------------------------------------
 1 | To transfer an eosio token, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`transfer`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L83) action of the account storing the token you wish to transfer.
 2 | 
 3 | In the example shown below `useraaaaaaaa` transfers **1.0000 EOS** token stored in the `eosio.token` account from `useraaaaaaaa` to `userbbbbbbbb`.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio.token',
 9 |       name: 'transfer',
10 |       authorization: [{
11 |         actor: 'useraaaaaaaa',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         from: 'useraaaaaaaa',
16 |         to: 'userbbbbbbbb',
17 |         quantity: '1.0000 EOS',
18 |         memo: 'some memo'
19 |       }
20 |     }]
21 |   }, {
22 |     blocksBehind: 3,
23 |     expireSeconds: 30,
24 |   });
25 | })();
26 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/09_how-to-get-table-information.md:
--------------------------------------------------------------------------------
  1 | There are many ways to retrieve data stored in smart contract tables.  A few are provided below.
  2 | 
  3 | ## Get Table Rows
  4 | In the example shown below, the `eosio.token` smart contract's table `accounts` is queried with the scope `testacc`.  The data is returned as **json**, in-order, and limited to **10 rows**.  The RAM payer for the returned row is also not shown.
  5 | ```javascript
  6 | (async () => {
  7 |   await rpc.get_table_rows({
  8 |     json: true,               // Get the response as json
  9 |     code: 'eosio.token',      // Contract that we target
 10 |     scope: 'testacc',         // Account that owns the data
 11 |     table: 'accounts',        // Table name
 12 |     limit: 10,                // Maximum number of rows that we want to get
 13 |     reverse: false,           // Optional: Get reversed data
 14 |     show_payer: false          // Optional: Show ram payer
 15 |   });
 16 | })();
 17 | ```
 18 | Above we console log the response from the EOSIO network.  An example of an expected response is shown below.
 19 | ```javascript
 20 | {
 21 |   rows: [ { balance: '68.3081 EOS' }, { balance: '200.0000 JUNGLE' } ],
 22 |   more: false
 23 | }
 24 | ```
 25 | Note that since `more: false` was returned, if can be inferred that there are only 2 rows with scope `testacc` in the `accounts` table of the `eosio.token` smart contract.
 26 | 
 27 | ## Get Currency Balance
 28 | Rather than using the `get_table_rows` method, a token balance can also be retrieved using the `get_currency_balance` method.  This method takes an `account` which is a smart contract storing the tokens, an `account` who has a balance in the token table of the specified smart contract, and the `symbol` of the token to retrieve the currency balance for.
 29 | 
 30 | In the example shown below, the balance of the user `testacc`'s tokens with the symbol `EOS` stored in the `eosio.token` smart contract is retrieved.
 31 | ```javascript
 32 | (async () => {
 33 |   console.log(await rpc.get_currency_balance('eosio.token', 'testacc', 'EOS'));
 34 | })();
 35 | ```
 36 | Above we console log the response from the EOSIO network.  An example of an expected response is shown below.
 37 | ```javascript
 38 | [ '68.3081 EOS' ]
 39 | ```
 40 | 
 41 | ## Query By Index
 42 | A `lower_bound` parameter can also be passed to the `get_table_rows` method.  This parameter allows you to query for a particular value of the primary key in the table.  Using this in conjunction with `limit: 1` allows you to query for 1 row of a table.
 43 | 
 44 | In the example shown below, the `contract` smart contract's table `profiles` is queried with the scope `contract` for the row with primary key `testacc`.  The `limit` is **1** which implies that only 1 row with value `testacc` will be returned.
 45 | ```javascript
 46 | (async () => {
 47 |   console.log(await rpc.get_table_rows({
 48 |     json: true,                 // Get the response as json
 49 |     code: 'contract',           // Contract that we target
 50 |     scope: 'contract',          // Account that owns the data
 51 |     table: 'profiles',          // Table name
 52 |     lower_bound: 'testacc',     // Table primary key value
 53 |     limit: 1,                   // Here we limit to 1 to get only the single row with primary key equal to 'testacc'
 54 |     reverse: false,             // Optional: Get reversed data
 55 |     show_payer: false,          // Optional: Show ram payer
 56 |   }));
 57 | })();
 58 | ```
 59 | Above we console log the response from the EOSIO network.  An example of an expected response is shown below.
 60 | ```javascript
 61 | {
 62 |   "rows": [{
 63 |       "user": "testacc",
 64 |       "age": 21,
 65 |       "surname": "Martin"
 66 |     }
 67 |   ],
 68 |   "more": false
 69 | }
 70 | ```
 71 | 
 72 | ## Query By Secondary Index
 73 | Finally, the `lower_bound` parameter can be used in conjunction with the `index_position` parameter to query an index different from the primary key.
 74 | 
 75 | In the example shown below, the `contract` smart contract's table `profiles` is queried with the scope `contract` for the rows with secondary index `age` equal to **21**.  The `limit` is **1** which implies that only 1 row with the age **21** will be returned.
 76 | ```javascript
 77 | (async () => {
 78 |   console.log(await rpc.get_table_rows({
 79 |     json: true,                 // Get the response as json
 80 |     code: 'contract',           // Contract that we target
 81 |     scope: 'contract',          // Account that owns the data
 82 |     table: 'profiles',          // Table name
 83 |     index_position: 2,          // Table secondary index
 84 |     lower_bound: 21,            // Table secondary key value
 85 |     limit: 1,                   // Here we limit to 1 to get only row
 86 |     reverse: false,             // Optional: Get reversed data
 87 |     show_payer: false,          // Optional: Show ram payer
 88 |   }));
 89 | })();
 90 | ```
 91 | 
 92 | ## Query Data using the Key-Value API (KV API) 
 93 | The KV API is a new api which allows smart contract developers to create datastore key value tables on-chain. KV tables can have multiple indices, unique indices and non-unique indices. The table must have at least one unique index. If the smart contract uses KV tables use the get_kv_table_rows RPC call to query data.
 94 | 
 95 | In the example shown below, the `contract` smart contract's kv table `profiles` is queried via the index named `users` for the row with primary key `testacc`.  The `limit` is **1** which implies that only 1 row with value `testacc` will be returned.
 96 | ```javascript
 97 | (async () => {
 98 |   console.log(await rpc.get_kv_table_rows({
 99 |     json: false,               	// Get the response as json
100 |     code: 'contract',          	// Contract that we target
101 |     table: 'profiles',         	// Tablename
102 |     indexName: 'users',     	// The name of the index name
103 |     indexValue: 'testacc',     	// Table primary key value
104 | 	limit: 1,                  	// Here we limit to 1 to get only the single row with primary key equal to 'testacc'
105 |     reverse: false,            	// Optional: Get reversed data
106 |     show_payer: false,         	// Optional: Show ram payer
107 |   }));
108 | })();
109 | ```
110 | Above we console log the response from the EOSIO network.  An example of an expected response is shown below.
111 | ```javascript
112 | {
113 |   "rows": [{
114 |       "user": "testacc",
115 |       "age": 21,
116 |       "surname": "Martin"
117 |     }
118 |   ],
119 |   "more": false
120 | }
121 | ```
122 | 
123 | If the KV table has an additional indexes these can be used to query the data.  The example shown below, is based on the previous example however in this case an index called `ages` is defined. This index is used to query the table for records where the persons age is 17. 
124 | ```javascript
125 | (async () => {
126 |   console.log(await rpc.get_kv_table_rows({
127 |     json: false,               	// Get the response as json
128 |     code: 'contract',          	// Contract that we target
129 |     table: 'profiles',         	// Tablename
130 |     indexName: 'ages',     		// The name of the index name
131 |     lowerBound: '17',     		// Table primary key value
132 |     upperBound: '17',     		// Table primary key value
133 | 	limit: 1,                  	// Here we limit to 1 to get only the single row with primary key equal to 'testacc'
134 |     reverse: false,            	// Optional: Get reversed data
135 |     show_payer: false,         	// Optional: Show ram payer
136 |   }));
137 | })();
138 | ```
139 | Above we console log the response from the EOSIO network.  An example of an expected response is shown below.
140 | ```javascript
141 | {
142 |   "rows": [{
143 |       "user": "otheracc",
144 |       "age": 17,
145 |       "surname": "Dubious"
146 |     }
147 |   ],
148 |   "more": false
149 | }
150 | ```
151 | 


--------------------------------------------------------------------------------
/docs/how-to-guides/10_how-to-create-permissions.md:
--------------------------------------------------------------------------------
 1 | To create new permissions, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`updateauth`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp#L205) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` creates a new permission called `my_new_permission` on the account `useraaaaaaaa`, with the public key `PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu`.
 4 | ```javascript
 5 | const authorization_object = { 
 6 |   threshold: 1, 
 7 |   accounts: [{
 8 |     permission: {
 9 |       actor: "useraaaaaaaa", 
10 |       permission: "active"
11 |     }, 
12 |     weight: 1 
13 |   }], 
14 |   keys: [{ 
15 |     key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu', 
16 |     weight: 1 
17 |   }],
18 |   waits: []
19 | };
20 | 
21 | const updateauth_input = {
22 |   account: 'useraaaaaaaa',
23 |   permission: 'my_new_permission',
24 |   parent: 'active',
25 |   auth: authorization_object
26 | };
27 | 
28 | (async () => {
29 |   await api.transact({
30 |     actions: [
31 |     {
32 |       account: 'eosio',
33 |       name: 'updateauth',
34 |       authorization: [{
35 |         actor: 'useraaaaaaaa',
36 |         permission: 'active',
37 |       }],
38 |       data: updateauth_input,
39 |     }]
40 |   }, {
41 |     blocksBehind: 3,
42 |     expireSeconds: 30,
43 |   });
44 | })();
45 | ```
46 | You can check that the new permission exists on the account using [`get_account`](07_how-to-get-account-information.md)


--------------------------------------------------------------------------------
/docs/how-to-guides/11_how-to-delete-permissions.md:
--------------------------------------------------------------------------------
 1 | To delete permissions, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`deleteauth`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp#L219) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` deletes the permission `my_new_permission` on the account `useraaaaaaaa`.
 4 | ```javascript
 5 | const deleteauth_input = {
 6 |   account: 'useraaaaaaaa',
 7 |   permission: 'my_new_permission',
 8 | };
 9 | 
10 | (async () => {
11 |   await api.transact({
12 |     actions: [
13 |     {
14 |       account: 'eosio',
15 |       name: 'deleteauth',
16 |       authorization: [{
17 |         actor: 'useraaaaaaaa',
18 |         permission: 'active',
19 |       }],
20 |       data: delete_auth_data,
21 |     }]
22 |   }, {
23 |     blocksBehind: 3,
24 |     expireSeconds: 30,
25 |   });
26 | })();
27 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/12_how-to-link-permissions.md:
--------------------------------------------------------------------------------
 1 | To link an existing permission, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`linkauth`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp#L240) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` links the permission `action_perm` to the contract `useraaaaaaaa`'s `contract_action` action.
 4 | ```javascript
 5 | const linkauth_input = {
 6 |   account: 'useraaaaaaaa',      // the permission's owner to be linked and the payer of the RAM needed to store this link
 7 |   code: 'useraaaaaaaa',         // the owner of the action to be linked
 8 |   type: 'contract_action',      // the action to be linked
 9 |   requirement: 'action_perm',   // the permission to be linked
10 | };
11 | 
12 | (async () => {
13 |   await api.transact({
14 |     actions: [{
15 |       account: 'eosio',
16 |       name: 'linkauth',
17 |       authorization: [{
18 |         actor: 'useraaaaaaaa',
19 |         permission: 'active',
20 |       }],
21 |       data: linkauth_input,
22 |     }]
23 |   }, {
24 |     blocksBehind: 3,
25 |     expireSeconds: 30,
26 |   }));
27 | })();
28 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/12_how-to-unlink-permissions.md:
--------------------------------------------------------------------------------
 1 | To unlink an existing permission, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`unlinkauth`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp#L255) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` unlinks the permissions present on the contract `useraaaaaaaa`'s `contract_action` action.
 4 | ```javascript
 5 | const unlinkauth_input = {
 6 |   account: 'useraaaaaaaa',      // the permission's owner to be linked and the payer of the RAM needed to store this link
 7 |   code: 'useraaaaaaaa',         // the owner of the action to be linked
 8 |   type: 'contract_action'       // the action to be linked
 9 | };
10 | 
11 | (async () => {
12 |   await api.transact({
13 |     actions: [{
14 |       account: 'eosio',
15 |       name: 'unlinkauth',
16 |       authorization: [{
17 |         actor: 'useraaaaaaaa',
18 |         permission: 'active',
19 |       }],
20 |       data: unlinkauth_input,
21 |     }]
22 |   }, {
23 |    blocksBehind: 3,
24 |    expireSeconds: 30,
25 |   });
26 | })();
27 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/13_how-to-propose-a-multisig-transaction.md:
--------------------------------------------------------------------------------
  1 | To propose a transaction, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`propose`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp#L39) action of the `eosio.msig` account.
  2 | 
  3 | ## Serializing Actions
  4 | The `data` field of the `propose` action has a `tx` field, which is a [`transaction`](https://github.com/EOSIO/eosio.contracts/blob/6ca72e709faba179726a20571929a9eeaea47d08/tests/test_contracts/eosio.msig.old/eosio.msig.abi#L48) type.  This `transaction` type contains an [`action`](https://github.com/EOSIO/eosio.contracts/blob/6ca72e709faba179726a20571929a9eeaea47d08/tests/test_contracts/eosio.msig.old/eosio.msig.abi#L21) type, which contains [`bytes`](https://github.com/EOSIO/eosio.contracts/blob/6ca72e709faba179726a20571929a9eeaea47d08/tests/test_contracts/eosio.msig.old/eosio.msig.abi#L27) as it's `data` field.  Because of this, we must first serialize a list of [`action`](https://github.com/EOSIO/eosio.contracts/blob/6ca72e709faba179726a20571929a9eeaea47d08/tests/test_contracts/eosio.msig.old/eosio.msig.abi#L21) objects.
  5 | 
  6 | ## serializeActions
  7 | In the example shown below, a transaction for the `eosio` `updateauth` action is serialized using the `api` object's `serializeActions` method.
  8 | ```javascript
  9 | const actions = [
 10 |   {
 11 |     account: 'eosio',
 12 |     name: 'updateauth',
 13 |     authorization: [
 14 |       {
 15 |         actor: 'useraaaaaaaa',
 16 |         permission: 'active',
 17 |       }
 18 |     ],
 19 |     data: {
 20 |       account: 'useraaaaaaaa',
 21 |       permission: 'active',
 22 |       parent: '',
 23 |       auth: {
 24 |         threshold: 1,
 25 |         keys: [
 26 |           {
 27 |             key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu',
 28 |             weight: 1
 29 |           }
 30 |         ],
 31 |         accounts:[],
 32 |         waits:[]
 33 |       }
 34 |     }
 35 |   }
 36 | ];
 37 | 
 38 | (async () => {
 39 |   const serialized_actions = await api.serializeActions(actions)
 40 | }
 41 | ```
 42 | An example output of `serialized_actions` call made above is shown below.
 43 | ```javascript
 44 | [
 45 |   {
 46 |     account: 'eosio',
 47 |     name: 'updateauth',
 48 |     authorization: [ [Object] ],
 49 |     data: 'F0F0C30F3FFCF0C300000000A8ED3232000000000000000001000000010003FD9ABF3D22615D5621BF74D2D0A652992DE1338E552AD85D5EAF1F39DCAADDB301000000'
 50 |   }
 51 | ]
 52 | ```
 53 | 
 54 | ## Propose Input
 55 | In the example shown below, the `serialized_actions` list created above is used in the `actions` field of the `proposeInput`'s `trx` field.
 56 | 
 57 | [Below](#propose) `useraaaaaaaa` proposes a multi-sig transaction, which calls the `updateauth` action of the `eosio` account (see [`actions`](#serializeactions) above).  This proposal is called `changeowner` and both `useraaaaaaaa` and `userbbbbbbbb` must sign the multi-sig transaction before `2019-09-14T16:39:15`.
 58 | ```javascript
 59 | const proposeInput = {
 60 |     proposer: 'useraaaaaaaa',
 61 |     proposal_name: 'changeowner',
 62 |     requested: [
 63 |       {
 64 |         actor: 'useraaaaaaaa',
 65 |         permission: 'active'
 66 |       },
 67 |       {
 68 |         actor: 'userbbbbbbbb',
 69 |         permission: 'active'
 70 |       }
 71 |     ],
 72 |     trx: {
 73 |       expiration: '2019-09-14T16:39:15',
 74 |       ref_block_num: 0,
 75 |       ref_block_prefix: 0,
 76 |       max_net_usage_words: 0,
 77 |       max_cpu_usage_ms: 0,
 78 |       delay_sec: 0,
 79 |       context_free_actions: [],
 80 |       actions: serialized_actions,
 81 |       transaction_extensions: []
 82 |     }
 83 |   };
 84 | ```
 85 | 
 86 | ## Propose
 87 | In the example below, a transaction is submitted to the `propose` action of the `eosio.msig` contract using the `proposeInput` object created [above](#propose-input).
 88 | ```javascript
 89 | await api.transact({
 90 |   actions: [{
 91 |     account: 'eosio.msig',
 92 |     name: 'propose',
 93 |     authorization: [{
 94 |       actor: 'useraaaaaaaa',
 95 |       permission: 'active',
 96 |     }],
 97 |     data: proposeInput,
 98 |   }]
 99 | }, {
100 |   blocksBehind: 3,
101 |   expireSeconds: 30,
102 |   broadcast: true,
103 |   sign: true
104 | });
105 | ```
106 | 
107 | ## Propose a Multi-sig Transaction
108 | Below all three steps to propose a multi-sig transaction are provided.
109 | 
110 | ```javascript
111 | // CREATE ACTION TO PROPOSE
112 | const actions = [
113 |   {
114 |     account: 'eosio',
115 |     name: 'updateauth',
116 |     authorization: [
117 |       {
118 |         actor: 'useraaaaaaaa',
119 |         permission: 'active',
120 |       }
121 |     ], data: {
122 |       account: 'useraaaaaaaa',
123 |       permission: 'active',
124 |       parent: '',
125 |       auth: {
126 |         threshold: 1,
127 |         keys: [
128 |           {
129 |             key: 'PUB_R1_6FPFZqw5ahYrR9jD96yDbbDNTdKtNqRbze6oTDLntrsANgQKZu',
130 |             weight: 1
131 |           }
132 |         ],
133 |         accounts:[],
134 |         waits:[]
135 |       }
136 |     },
137 |   }
138 | ];
139 | 
140 | (async () => {
141 |   const serialized_actions = await api.serializeActions(actions)
142 | 
143 |   // BUILD THE MULTISIG PROPOSE TRANSACTION
144 |   proposeInput = {
145 |     proposer: 'useraaaaaaaa',
146 |     proposal_name: 'changeowner',
147 |     requested: [
148 |       {
149 |         actor: 'useraaaaaaaa',
150 |         permission: 'active'
151 |       },
152 |       {
153 |         actor: 'userbbbbbbbb',
154 |         permission: 'active'
155 |       }
156 |     ],
157 |     trx: {
158 |       expiration: '2019-09-16T16:39:15',
159 |       ref_block_num: 0,
160 |       ref_block_prefix: 0,
161 |       max_net_usage_words: 0,
162 |       max_cpu_usage_ms: 0,
163 |       delay_sec: 0,
164 |       context_free_actions: [],
165 |       actions: serialized_actions,
166 |       transaction_extensions: []
167 |     }
168 |   };
169 | 
170 |   //PROPOSE THE TRANSACTION
171 |   const result = await api.transact({
172 |     actions: [{
173 |       account: 'eosio.msig',
174 |       name: 'propose',
175 |       authorization: [{
176 |         actor: 'useraaaaaaaa',
177 |         permission: 'active',
178 |       }],
179 |       data: proposeInput,
180 |     }]
181 |   }, {
182 |     blocksBehind: 3,
183 |     expireSeconds: 30,
184 |     broadcast: true,
185 |     sign: true
186 |   });
187 | })();
188 | ```
189 | 


--------------------------------------------------------------------------------
/docs/how-to-guides/14_how-to-approve-a-multisig-transaction.md:
--------------------------------------------------------------------------------
 1 | To approve a multi-sig transaction, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`approve`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp#L58) action of the `eosio.msig` account.
 2 | 
 3 | In the example shown below `userbbbbbbbb` approves the `changeowner` proposal, previously proposed by `useraaaaaaaa` using `userbbbbbbbb`'s `active` permission.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio.msig',
 9 |       name: 'approve',
10 |       authorization: [{
11 |         actor: 'userbbbbbbbb',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         proposer: 'useraaaaaaaa',
16 |         proposal_name: 'changeowner',
17 |         level: {
18 |           actor: 'userbbbbbbbb',
19 |           permission: 'active',
20 |         }
21 |       },
22 |     }]
23 |   }, {
24 |     blocksBehind: 3,
25 |     expireSeconds: 30,
26 |     broadcast: true,
27 |     sign: true
28 |   });
29 | })();
30 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/15_how-to-unapprove-a-multisig-transaction.md:
--------------------------------------------------------------------------------
 1 | To unapprove a multi-sig transaction, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`unapprove`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp#L73) action of the `eosio.msig` account.
 2 | 
 3 | In the example shown below `userbbbbbbbb` unapproves the `changeowner` proposal, previously proposed by `useraaaaaaaa` using `userbbbbbbbb`'s `active` permission.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio.msig',
 9 |       name: 'unapprove',
10 |       authorization: [{
11 |         actor: 'userbbbbbbbb',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         proposer: 'useraaaaaaaa',
16 |         proposal_name: 'changeowner',
17 |         level: {
18 |           actor: 'userbbbbbbbb',
19 |           permission: 'active',
20 |         }
21 |       },
22 |     }]
23 |   }, {
24 |     blocksBehind: 3,
25 |     expireSeconds: 30,
26 |     broadcast: true,
27 |     sign: true
28 |   });
29 | })();
30 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/16_how-to-cancel-a-multisig-transaction.md:
--------------------------------------------------------------------------------
 1 | To cancel a multi-sig transaction, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`cancel`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp#L88) action of the `eosio.msig` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` cancels the `changeowner` proposal, previously proposed by `useraaaaaaaa`.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio.msig',
 9 |       name: 'cancel',
10 |       authorization: [{
11 |         actor: 'useraaaaaaaa',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         proposer: 'useraaaaaaaa',
16 |         proposal_name: 'changeowner',
17 |         canceler: 'useraaaaaaaa'
18 |       },
19 |     }]
20 |   }, {
21 |     blocksBehind: 3,
22 |     expireSeconds: 30,
23 |     broadcast: true,
24 |     sign: true
25 |   });
26 | })();
27 | ```
28 | 
29 | **Note** that if a previously proposed transaction has yet to expire, only the proposer of the transaction can cancel it.


--------------------------------------------------------------------------------
/docs/how-to-guides/17_how-to-execute-a-multisig-transaction.md:
--------------------------------------------------------------------------------
 1 | If a multi-sig transaction has been approved by the appropriate parties prior to the proposed transaction's expiration timestamp, it can be executed.
 2 | 
 3 | To execute a multi-sig transaction, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`exec`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp#L109) action of the `eosio.msig` account.
 4 | 
 5 | In the example shown below `userbbbbbbbb` executes the `changeowner` proposal, previously proposed by `useraaaaaaaa`.
 6 | ```javascript
 7 | (async () => {
 8 |   await api.transact({
 9 |     actions: [{
10 |       account: 'eosio.msig',
11 |       name: 'exec',
12 |       authorization: [{
13 |         actor: 'userbbbbbbbb',
14 |         permission: 'active',
15 |       }],
16 |       data: {
17 |         proposer: 'useraaaaaaaa',
18 |         proposal_name: 'changeowner',
19 |         executer: 'userbbbbbbbb'
20 |       },
21 |     }]
22 |   }, {
23 |     blocksBehind: 3,
24 |     expireSeconds: 30,
25 |     broadcast: true,
26 |     sign: true
27 |   });
28 | })();
29 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/18_how-to-vote.md:
--------------------------------------------------------------------------------
 1 | To vote for a block produder, [submit a transaction](01_how-to-submit-a-transaction.md) to the [`voteproducer`](https://github.com/EOSIO/eosio.contracts/blob/52fbd4ac7e6c38c558302c48d00469a4bed35f7c/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L1130) action of the `eosio` account.
 2 | 
 3 | In the example shown below `useraaaaaaaa` votes for producers `userbbbbbbbb` and `usercccccccc`.
 4 | ```javascript
 5 | (async () => {
 6 |   await api.transact({
 7 |     actions: [{
 8 |       account: 'eosio',
 9 |       name: 'voteproducer',
10 |       authorization: [{
11 |         actor: 'useraaaaaaaa',
12 |         permission: 'active',
13 |       }],
14 |       data: {
15 |         voter: 'useraaaaaaaa',
16 |         proxy: '',
17 |         producers: ['userbbbbbbbb', 'usercccccccc']
18 |       },
19 |     }]
20 |   }, {
21 |     blocksBehind: 3,
22 |     expireSeconds: 30,
23 |     broadcast: true,
24 |     sign: true
25 |   });
26 | })();
27 | ```
28 | 
29 | `useraaaaaaaa` can also delegate their vote to a proxy.  In the example shown below, `useraaaaaaaa` delegates their vote to the proxy `userbbbbbbbb`.
30 | ```javascript
31 | (async () => {
32 |   await api.transact({
33 |     actions: [{
34 |       account: 'eosio',
35 |       name: 'voteproducer',
36 |       authorization: [{
37 |         actor: 'useraaaaaaaa',
38 |         permission: 'active',
39 |       }],
40 |       data: {
41 |         voter: 'useraaaaaaaa',
42 |         proxy: 'userbbbbbbbb',
43 |         producers: []
44 |       },
45 |     }]
46 |   }, {
47 |     blocksBehind: 3,
48 |     expireSeconds: 30,
49 |     broadcast: true,
50 |     sign: true
51 |   });
52 | })();
53 | ```
54 | 
55 | **Note** that if the `proxy` field is used, the `producers` list must be empty, and vice verse, if the `producers` list is used, the `proxy` field must be an empty string.


--------------------------------------------------------------------------------
/docs/how-to-guides/19_how-to-set-the-network.md:
--------------------------------------------------------------------------------
 1 | To change the network used by `eosjs`, pass in the URL of a node connected to the network of interest to `JsonRpc`.
 2 | 
 3 | In the examples shown in the `basic-usage` section, it was assumed that a local node running on port `8888` was used.
 4 | ```javascript
 5 | const rpc = new JsonRpc('http://127.0.0.1:8888');
 6 | ```
 7 | 
 8 | However, the address and port of any node on any network can be used by passing in the URL of the node as a string to the `JsonRpc` object.  Assuming there is a node running at the IP address `192.168.2.1` listening for requests on port `9999`, we could connect to this node and it's network with the following line of code.
 9 | ```javascript
10 | const rpc = new JsonRpc('http://192.168.2.1:9999');
11 | ```


--------------------------------------------------------------------------------
/docs/how-to-guides/20_how-to-set-a-payer.md:
--------------------------------------------------------------------------------
 1 | After the release of v2.2 of nodeos, the resource payer feature is available to sponsor the resources for a transaction.  To set a separate payer for the resources for a transaction, add a `resource_payer` object to your transaction that specifies the `payer`, `max_net_bytes`, `max_cpu_us`, and `max_memory_bytes`.  This functionality requires the `RESOURCE_PAYER` protocol feature to be enabled on the chain.
 2 | 
 3 | A typical use-case for this feature has a service or application pay for the resources of a transaction instead of their users. Since authorization is required for both the user in the transaction and the payer, a possible workflow would have the transaction signed by the user's wallet application and then also signed by the service/application before sent to nodeos.
 4 | 
 5 | ```javascript
 6 | {
 7 |     resource_payer: {
 8 |         payer: 'alice',
 9 |         max_net_bytes: 4096,
10 |         max_cpu_us: 400,
11 |         max_memory_bytes: 0
12 |     },
13 |     actions: [{
14 |         account: 'eosio.token',
15 |         name: 'transfer',
16 |         authorization: [{
17 |             actor: 'bob',
18 |             permission: 'active',
19 |         }, {
20 |             actor: 'alice',
21 |             permission: 'active',
22 |         }],
23 |         data: {
24 |             from: 'bob',
25 |             to: 'alice',
26 |             quantity: '0.0001 SYS',
27 |             memo: 'resource payer',
28 |         },
29 |     }]
30 | }
31 | ```
32 | 


--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | content_title: eosjs
 3 | ---
 4 | 
 5 | `eosjs` is a Javascript library which provides an API for integrating with EOSIO-based blockchains using the [EOSIO Nodeos RPC API](https://developers.eos.io/eosio-nodeos/reference).  The documentation for `eosjs` is structured in the following way:
 6 | 
 7 | * [Installation](02_installation.md) explains how to install `eosjs` using `npm` or `yarn`.
 8 | * [Basic Usage](basic-usage/) provides information related to importing `eosjs` in various Javascript environments.  The [basic-usage](basic-usage/index.md) document specifically provides brief explanations of the components provided by `eosjs` as well as their typical use cases.
 9 | * [FAQ](faq/) provides answers to frequently asked questions surrounding the `eosjs` software.
10 | * [How-To Guides](how-to-guides/) provides how-tos on everything from getting block information to proposing and signing multi-sig transactions.
11 | * [Troubleshooting](troubleshooting/) provides possible exceptions encountered when developing with `eosjs` and their most common causes.
12 | * [Technical Overview](01_technical-overview.md) provides a high-level overview of how `eosjs` works.
13 | 


--------------------------------------------------------------------------------
/docs/troubleshooting/00_connectivity.md:
--------------------------------------------------------------------------------
 1 | While troubleshooting network connectivity it is advisable to issue a `rpc.get_info()` request to rule out the possibility of `Api` object misconfiguration or authorization related problems.  Given the `JsonRpc` object only requires a node URL, this approach isolates problems to simple node connectivity problems.
 2 | 
 3 | Below are a number of ways a `rpc.get_info()` request can fail and what they could potentially mean.
 4 | 
 5 | ## invalid json response body
 6 | ```javascript
 7 | (node:66636) UnhandledPromiseRejectionWarning: FetchError: invalid json response body at http://www.some-node-url.com/v1/chain/get_info reason: Unexpected token < in JSON at position 0
 8 | ```
 9 | 
10 | This typically means you have connected to a computer that is not running EOSIO software.  For example, if you instantiate a `JsonRpc` object as follows:
11 | 
12 | ```javascript
13 | const rpc = new JsonRpc('http://some-node-url.com', { fetch });
14 | ```
15 | 
16 | You would see the exception above when issuing a `rpc.get_info()` request since the computer at `http://some-node-url.com` is not running EOSIO software.
17 | 
18 | ## ETIMEDOUT
19 | ```javascript
20 | (node:68313) UnhandledPromiseRejectionWarning: FetchError: request to http://some-node-url.com:8000/v1/chain/get_info failed, reason: connect ETIMEDOUT 53.140.50.180:8000
21 | ```
22 | 
23 | This typically implies you have connected to a node that *is* running EOSIO software, but have entered the incorrect port, or left off the port number altogether.
24 | 
25 | ## Indefinite Hanging
26 | If the `rpc.get_info()` request never returns, but also never throws an exception, it is likely that you've connected to a node running EOSIO software, but have misconfigured the protocol (http/https).
27 | 
28 | ## Only absolute URLs are supported
29 | ```javascript
30 | (node:72394) UnhandledPromiseRejectionWarning: TypeError: Only absolute URLs are supported
31 | ```
32 | 
33 | This typically implies you've entered an empty string as the first argument to `JsonRpc` as shown below.
34 | 
35 | ```javascript
36 | const rpc = new JsonRpc('', { fetch });
37 | ```
38 | 
39 | ## Only HTTP(S) protocols are supported
40 | ```javascript
41 | (node:72612) UnhandledPromiseRejectionWarning: TypeError: Only HTTP(S) protocols are supported
42 | ```
43 | This typically implies you've left off the protocol from the absolute URL string (i.e. `127.0.0.1:8888` rather than `http://127.0.0.1:8888`).
44 | 
45 | 
46 | ## ENOTFOUND
47 | ```javascript
48 | (node:72822) UnhandledPromiseRejectionWarning: FetchError: request to http://www.some-node-url.com:8888/v1/chain/get_info failed, reason: getaddrinfo ENOTFOUND www.some-node-url.com
49 | ```
50 | This typically implies you've misconfigured the domain name of the absolute URL in some way.  Adding `www.` erroneously or removing `.com` at the end of the domain name could be possible mistakes.
51 | 
52 | ## f is not a function
53 | ```javascript
54 | (node:74052) UnhandledPromiseRejectionWarning: TypeError: f is not a function
55 | ```
56 | This typically implies the absolute URL string of the node was not passed to the `JsonRpc` object as show below
57 | 
58 | ```javascript
59 | const rpc = new JsonRpc({ fetch });
60 | ```
61 | 


--------------------------------------------------------------------------------
/docs/troubleshooting/01_missing-authorizations.md:
--------------------------------------------------------------------------------
 1 | Below are a number of ways authorization related requests can fail and what the failure could potentially mean.
 2 | 
 3 | ## transaction declares authority but does not have signatures for it.
 4 | ```javascript
 5 | (node:99019) UnhandledPromiseRejectionWarning: Error: transaction declares authority '{"actor":"useraaaaaaaa","permission":"active"}', but does not have signatures for it.
 6 | ```
 7 | 
 8 | This exception can occur for a number of different reasons.
 9 | 
10 | It could be that the private key supplied to the signature provider is incorrect for the actor in which the transaction is being signed for.  It could also be that the `actor` field of the `authorization` object is incorrect.  Finally, it could be that the `permission` specified is incorrect or does not exist for the specified actor.
11 | 
12 | ## Invalid checksum
13 | ```javascript
14 | Error: Invalid checksum, 01b93f != 5df6e0e2
15 | ```
16 | 
17 | This typically implies the private key supplied to the `JsSignatureProvider` object is malformed or invalid.
18 | 
19 | ## Cannot read property 'length' of undefined
20 | ```javascript
21 | (node:97736) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'length' of undefined
22 | ```
23 | 
24 | This typically implies you have not supplied an `authorization` field in the `action` supplied to the `transact` method of the `api` object.
25 | 
26 | For example, the below request would cause the above exception, since the `authorization` field is not present.
27 | ```javascript
28 | (async () => {
29 |   await api.transact({
30 |    actions: [{
31 |      account: 'eosio',
32 |      name: 'buyrambytes',
33 |      data: {
34 |        payer: 'useraaaaaaaa',
35 |        receiver: 'useraaaaaaaa',
36 |        bytes: 8192,
37 |      },
38 |    }]
39 |   }, {
40 |    blocksBehind: 3,
41 |    expireSeconds: 30,
42 |   });
43 | })();
44 | ```
45 | 
46 | ## missing permission_level
47 | ```javascript
48 | (node:472) UnhandledPromiseRejectionWarning: Error: missing permission_level.permission (type=name)
49 | ```
50 | 
51 | This means that you have left either the `actor` or `permission` field off of the `authorization` object of an action.
52 | 
53 | 


--------------------------------------------------------------------------------
/docs/troubleshooting/02_rpcerror.md:
--------------------------------------------------------------------------------
 1 | When a call to the chain_api is performed and fails, it will result in an RPCError object being generated which contains information on why the transaction failed.
 2 | 
 3 | The RPCError object will contain a concise error message, for instance 'Invalid transaction'. However additional details can be found in the `details` field and the `json` field. The `json` field holds the complete json response from nodeos. The `details` field specifically holds the error object in the `json` field. The data content of the `json` and `details` vary depending on the endpoint is used to call nodeos. Use the `details` field to quickly find error information.
 4 | 
 5 | In the `details` and `json` examples below, you can see that the error message may not contain enough information to discern what caused the action to fail. The error message contains `eosio_assert_message` assertion failure. Looking further at the details you can see an `overdrawn balance` message.
 6 | ```javascript
 7 | RpcError: eosio_assert_message assertion failure
 8 |     at new RpcError (eosjs-rpcerror.ts:20:13)
 9 |     at JsonRpc. (eosjs-jsonrpc.ts:90:23)
10 |     at step (eosjs-jsonrpc.js:37:23)
11 |     at Object.next (eosjs-jsonrpc.js:18:53)
12 |     at fulfilled (eosjs-jsonrpc.js:9:58)
13 |     at processTicksAndRejections (node:internal/process/task_queues:94:5) {
14 |     details: {
15 |         code: 3050003,
16 |         name: 'eosio_assert_message_exception',
17 |         message: 'eosio_assert_message assertion failure',
18 |         stack: [
19 |             {
20 |                 context: {
21 |                     level: 'error',
22 |                     file: 'cf_system.cpp',
23 |                     line: 14,
24 |                     method: 'eosio_assert',
25 |                     hostname: '',
26 |                     thread_name: 'nodeos',
27 |                     timestamp: '2021-06-16T05:26:03.665'
28 |                 },
29 |                 format: 'assertion failure with message: ${s}',
30 |                 data: { s: 'overdrawn balance' }
31 |             },
32 |             {
33 |                 context: {
34 |                     level: 'warn',
35 |                     file: 'apply_context.cpp',
36 |                     line: 143,
37 |                     method: 'exec_one',
38 |                     hostname: '',
39 |                     thread_name: 'nodeos',
40 |                     timestamp: '2021-06-16T05:26:03.665'
41 |                 },
42 |                 format: 'pending console output: ${console}',
43 |                 data: { console: '' }
44 |             }
45 |         ]
46 |     },
47 |     json: {
48 |         head_block_num: 1079,
49 |         head_block_id: '00003384ff2dd671472e8290e7ee0fbc00ee1f450ce5c10de0a9c245ab5b5b22',
50 |         last_irreversible_block_num: 1070,
51 |         last_irreversible_block_id: '00003383946519b67bac1a0f31898826b472d81fd40b7fccb49a2f486bd292d1',
52 |         code_hash: '800bb7fedd86155047064bffdaa3c32cca76cda40eb80f5c4a7676c7f57da579',
53 |         pending_transactions: [],
54 |         result: {
55 |             id: '01a0cbb6c0215df53f07ecdcf0fb750a4134938b38a72946a0f6f25cf3f43bcb',
56 |             block_num: 1079,
57 |             block_time: '2021-06-14T21:13:04.500',
58 |             producer_block_id: null,
59 |             receipt: null,
60 |             elapsed: 189,
61 |             net_usage: 137,
62 |             scheduled: false,
63 |             action_traces: [Array],
64 |             account_ram_delta: null,
65 |             except: [Object],
66 |             error_code: '10000000000000000000',
67 |             bill_to_accounts: []
68 |         }
69 |     },
70 |     isFetchError: true
71 | }
72 | ```
73 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "eosjs",
 3 |   "version": "22.1.0",
 4 |   "description": "Talk to eos API",
 5 |   "main": "dist/index.js",
 6 |   "scripts": {
 7 |     "cypress": "cypress run --spec 'cypress/integration/index.spec.js'",
 8 |     "cypress-ui": "cypress open",
 9 |     "prepare": "npm run build",
10 |     "lint": "eslint --ext .js,.jsx,.ts,.tsx src",
11 |     "test": "jest src/tests/*eosjs*",
12 |     "test-node": "jest src/tests/*node*",
13 |     "test-types": "jest src/tests/type-checks.test.ts",
14 |     "test-all": "yarn test && yarn test-node && yarn test-types && yarn cypress",
15 |     "build": "rimraf dist && tsc -p ./tsconfig.json && node scripts/copy-ripe-md.js",
16 |     "build-web": "webpack --config webpack.prod.js && webpack --config webpack.debug.js",
17 |     "build-production": "yarn build && yarn build-web && yarn test-all",
18 |     "docs-init": "sh .docs/scripts/init.sh",
19 |     "docs-build": "sh .docs/scripts/build.sh",
20 |     "docs-serve": "python -m SimpleHTTPServer",
21 |     "docs-publish": "sh .docs/scripts/publish.sh"
22 |   },
23 |   "author": "block.one",
24 |   "license": "MIT",
25 |   "repository": {
26 |     "type": "git",
27 |     "url": "https://github.com/EOSIO/eosjs.git"
28 |   },
29 |   "dependencies": {
30 |     "bn.js": "5.2.0",
31 |     "elliptic": "6.5.4",
32 |     "hash.js": "1.1.7",
33 |     "pako": "2.0.3"
34 |   },
35 |   "devDependencies": {
36 |     "@blockone/eslint-config-blockone": "^4.0.1",
37 |     "@cypress/skip-test": "^2.6.1",
38 |     "@types/elliptic": "^6.4.13",
39 |     "@types/jest": "^26.0.24",
40 |     "@types/node": "^14.17.5",
41 |     "@types/node-fetch": "^2.5.11",
42 |     "@types/pako": "^1.0.2",
43 |     "buffer": "^6.0.3",
44 |     "clean-webpack-plugin": "^3.0.0",
45 |     "crypto-browserify": "^3.12.0",
46 |     "cypress": "^7.7.0",
47 |     "eosjs-ecc": "^4.0.7",
48 |     "eslint": "^7.30.0",
49 |     "jest": "^26.6.3",
50 |     "jest-extended": "^0.11.5",
51 |     "jest-fetch-mock": "^3.0.3",
52 |     "rimraf": "^3.0.2",
53 |     "ts-jest": "^26.5.6",
54 |     "ts-loader": "^9.2.3",
55 |     "typescript": "^4.3.5",
56 |     "webpack": "^5.44.0",
57 |     "webpack-cli": "^4.7.2"
58 |   },
59 |   "jest": {
60 |     "automock": false,
61 |     "setupFiles": [
62 |       "./src/tests/setupJest.js"
63 |     ],
64 |     "setupFilesAfterEnv": [
65 |       "jest-extended"
66 |     ],
67 |     "moduleFileExtensions": [
68 |       "ts",
69 |       "tsx",
70 |       "js"
71 |     ],
72 |     "transform": {
73 |       "^.+\\.(tsx?)$": "ts-jest"
74 |     },
75 |     "globals": {
76 |       "ts-jest": {
77 |         "tsconfig": "tsconfig.json"
78 |       }
79 |     },
80 |     "testRegex": "(/src/.*(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
81 |     "testEnvironment": "node"
82 |   }
83 | }
84 | 


--------------------------------------------------------------------------------
/scripts/copy-ripe-md.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var root = __dirname.replace('scripts', '');
4 | 
5 | if(!fs.existsSync(path.join(root + 'dist')))
6 |     fs.mkdirSync(path.join(root + 'dist'));
7 | 
8 | fs.copyFileSync(path.join(root + 'src/ripemd.es5.js'), path.join(root + 'dist/ripemd.js'));


--------------------------------------------------------------------------------
/scripts/is_latest.sh:
--------------------------------------------------------------------------------
 1 | is_latest=false;
 2 | 
 3 | current_commit="$(git rev-parse HEAD)";
 4 | tags="$(git tag --sort=-creatordate)";
 5 | 
 6 | IFS='\n' read -ra arry <<< "$tags"
 7 | 
 8 | latest_tag="${arry[0]}"
 9 | 
10 | if [ "$latest_tag" == "" ]; then 
11 |     latest_tag="v0.0.0";
12 | else
13 |     tag_commit="$(git rev-list -n 1 ${latest_tag})";
14 |     if [ "$tag_commit" == "$current_commit" ]; then
15 |         is_latest=true;
16 |     fi
17 | fi
18 | 
19 | echo "tag_commit: ${tag_commit}";
20 | echo "current_commit: ${current_commit}";
21 | echo "is_latest: ${is_latest}";
22 | 
23 | export TRAVIS_IS_LATEST_TAG="$is_latest"


--------------------------------------------------------------------------------
/scripts/publish-edge.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | . "${TRAVIS_BUILD_DIR}/scripts/publish-utils.sh";
 4 | 
 5 | echo "Running on branch/tag ${TRAVIS_BRANCH}":
 6 | 
 7 | echo "Setting up git"
 8 | setup_git
 9 | 
10 | echo "Creating new version"
11 | git checkout -- .
12 | 
13 | git status 
14 | 
15 | # get the short commit hash to include in the npm package
16 | current_commit="$(git rev-parse --short HEAD)";
17 | 
18 | npm version prerelease -preid "${current_commit}" -no-git-tag-version
19 | 
20 | git commit -a -m "Updating version [skip ci]"
21 | 
22 | echo "Publish to NPM"
23 | 
24 | cp .npmrc.template $HOME/.npmrc 
25 | 
26 | npm publish --tag edge


--------------------------------------------------------------------------------
/scripts/publish-tag.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | . "${TRAVIS_BUILD_DIR}/scripts/publish-utils.sh";
 4 | 
 5 | if [[ "$TRAVIS_TAG" == "" ]]; then
 6 |   echo "No tag specified, skipping...";
 7 | else
 8 |   echo "Running on branch/tag ${TRAVIS_TAG}":
 9 | 
10 |   echo "Setting up git"
11 |   setup_git
12 | 
13 |   echo "Creating new version"
14 |   git checkout -- .
15 | 
16 |   git status
17 | 
18 |   npm version -no-git-tag-version $TRAVIS_TAG
19 | 
20 |   echo "Pushing to git"
21 |   git commit -a -m "Publishing version ${TRAVIS_TAG} [skip ci]"
22 | 
23 |   git push origin HEAD:${1}
24 | 
25 |   echo "Build and Publish to NPM"
26 | 
27 |   cp .npmrc.template $HOME/.npmrc 
28 | 
29 |   if [[ "$TRAVIS_TAG" == *"-beta"* ]]; then
30 |     echo "Publishing with beta tag to npm"
31 |     npm publish --tag beta
32 |   else
33 |     echo "Publishing with latest tag to npm"
34 |     npm publish
35 |   fi
36 | fi
37 | 
38 | 


--------------------------------------------------------------------------------
/scripts/publish-utils.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | setup_git() {
 4 |   # Set the user name and email to perform a commit locally. No changes are pushed.
 5 |   git config --global user.email "user@email.com"
 6 |   git config --global user.name "username"
 7 | }
 8 | 
 9 | ensure_version_match() {
10 |   VERSION="v$(cat package.json | grep version | cut -f2 -d ":" | tr -d '",\ ')"
11 |   TAG="$(echo $GITHUB_REF | grep tags | cut -f3 -d'/')"
12 |   [[ "$VERSION" == "$TAG" ]] && echo "Versions match." || exit 1
13 | }


--------------------------------------------------------------------------------
/src/PrivateKey.ts:
--------------------------------------------------------------------------------
  1 | import { BNInput, ec as EC } from 'elliptic';
  2 | import {
  3 |     Key,
  4 |     KeyType,
  5 |     privateKeyToLegacyString,
  6 |     privateKeyToString,
  7 |     stringToPrivateKey,
  8 | } from './eosjs-numeric';
  9 | import { constructElliptic, PublicKey, Signature } from './eosjs-key-conversions';
 10 | 
 11 | /** Represents/stores a private key and provides easy conversion for use with `elliptic` lib */
 12 | export class PrivateKey {
 13 |     constructor(private key: Key, private ec: EC) {}
 14 | 
 15 |     /** Instantiate private key from an `elliptic`-format private key */
 16 |     public static fromElliptic(privKey: EC.KeyPair, keyType: KeyType, ec?: EC): PrivateKey {
 17 |         if (!ec) {
 18 |             ec = constructElliptic(keyType);
 19 |         }
 20 |         return new PrivateKey({
 21 |             type: keyType,
 22 |             data: privKey.getPrivate().toArrayLike(Buffer, 'be', 32),
 23 |         }, ec);
 24 |     }
 25 | 
 26 |     /** Instantiate private key from an EOSIO-format private key */
 27 |     public static fromString(keyString: string, ec?: EC): PrivateKey {
 28 |         const privateKey = stringToPrivateKey(keyString);
 29 |         if (!ec) {
 30 |             ec = constructElliptic(privateKey.type);
 31 |         }
 32 |         return new PrivateKey(privateKey, ec);
 33 |     }
 34 | 
 35 |     /** Export private key as `elliptic`-format private key */
 36 |     public toElliptic(): EC.KeyPair {
 37 |         return this.ec.keyFromPrivate(this.key.data);
 38 |     }
 39 | 
 40 |     public toLegacyString(): string {
 41 |         return privateKeyToLegacyString(this.key);
 42 |     }
 43 | 
 44 |     /** Export private key as EOSIO-format private key */
 45 |     public toString(): string {
 46 |         return privateKeyToString(this.key);
 47 |     }
 48 | 
 49 |     /** Get key type from key */
 50 |     public getType(): KeyType {
 51 |         return this.key.type;
 52 |     }
 53 | 
 54 |     /** Retrieve the public key from a private key */
 55 |     public getPublicKey(): PublicKey {
 56 |         const ellipticPrivateKey = this.toElliptic();
 57 |         return PublicKey.fromElliptic(ellipticPrivateKey, this.getType(), this.ec);
 58 |     }
 59 | 
 60 |     /** Sign a message or hashed message digest with private key */
 61 |     public sign(data: BNInput, shouldHash: boolean = true, encoding: BufferEncoding = 'utf8'): Signature {
 62 |         if (shouldHash) {
 63 |             if (typeof data === 'string') {
 64 |                 data = Buffer.from(data, encoding);
 65 |             }
 66 |             data = this.ec.hash().update(data).digest();
 67 |         }
 68 |         let tries = 0;
 69 |         let signature: Signature;
 70 |         const isCanonical = (sigData: Uint8Array): boolean =>
 71 |             !(sigData[1] & 0x80) && !(sigData[1] === 0 && !(sigData[2] & 0x80))
 72 |             && !(sigData[33] & 0x80) && !(sigData[33] === 0 && !(sigData[34] & 0x80));
 73 |         const constructSignature = (options: EC.SignOptions): Signature => {
 74 |             const ellipticPrivateKey = this.toElliptic();
 75 |             const ellipticSignature = ellipticPrivateKey.sign(data, options);
 76 |             return Signature.fromElliptic(ellipticSignature, this.getType(), this.ec);
 77 |         };
 78 | 
 79 |         if (this.key.type === KeyType.k1) {
 80 |             do {
 81 |                 signature = constructSignature({canonical: true, pers: [++tries]});
 82 |             } while (!isCanonical(signature.toBinary()));
 83 |         } else {
 84 |             signature = constructSignature({canonical: true});
 85 |         }
 86 |         return signature;
 87 |     }
 88 | 
 89 |     /** Validate a private key */
 90 |     public isValid(): boolean {
 91 |         try {
 92 |             const ellipticPrivateKey = this.toElliptic();
 93 |             const validationObj = ellipticPrivateKey.validate();
 94 |             return validationObj.result;
 95 |         } catch {
 96 |             return false;
 97 |         }
 98 |     }
 99 | }
100 | 


--------------------------------------------------------------------------------
/src/PublicKey.ts:
--------------------------------------------------------------------------------
 1 | import { ec as EC } from 'elliptic';
 2 | import {
 3 |     Key,
 4 |     KeyType,
 5 |     publicKeyToLegacyString,
 6 |     publicKeyToString,
 7 |     stringToPublicKey,
 8 | } from './eosjs-numeric';
 9 | import { constructElliptic } from './eosjs-key-conversions';
10 | 
11 | /** Represents/stores a public key and provides easy conversion for use with `elliptic` lib */
12 | export class PublicKey {
13 |     constructor(private key: Key, private ec: EC) {}
14 | 
15 |     /** Instantiate public key from an EOSIO-format public key */
16 |     public static fromString(publicKeyStr: string, ec?: EC): PublicKey {
17 |         const key = stringToPublicKey(publicKeyStr);
18 |         if (!ec) {
19 |             ec = constructElliptic(key.type);
20 |         }
21 |         return new PublicKey(key, ec);
22 |     }
23 | 
24 |     /** Instantiate public key from an `elliptic`-format public key */
25 |     public static fromElliptic(publicKey: EC.KeyPair, keyType: KeyType, ec?: EC): PublicKey {
26 |         const x = publicKey.getPublic().getX().toArray('be', 32);
27 |         const y = publicKey.getPublic().getY().toArray('be', 32);
28 |         if (!ec) {
29 |             ec = constructElliptic(keyType);
30 |         }
31 |         return new PublicKey({
32 |             type: keyType,
33 |             data: new Uint8Array([(y[31] & 1) ? 3 : 2].concat(x)),
34 |         }, ec);
35 |     }
36 | 
37 |     /** Export public key as EOSIO-format public key */
38 |     public toString(): string {
39 |         return publicKeyToString(this.key);
40 |     }
41 | 
42 |     /** Export public key as Legacy EOSIO-format public key */
43 |     public toLegacyString(): string {
44 |         return publicKeyToLegacyString(this.key);
45 |     }
46 | 
47 |     /** Export public key as `elliptic`-format public key */
48 |     public toElliptic(): EC.KeyPair {
49 |         return this.ec.keyPair({
50 |             pub: Buffer.from(this.key.data),
51 |         });
52 |     }
53 | 
54 |     /** Get key type from key */
55 |     public getType(): KeyType {
56 |         return this.key.type;
57 |     }
58 | 
59 |     /** Validate a public key */
60 |     public isValid(): boolean {
61 |         try {
62 |             const ellipticPublicKey = this.toElliptic();
63 |             const validationObj = ellipticPublicKey.validate();
64 |             return validationObj.result;
65 |         } catch {
66 |             return false;
67 |         }
68 |     }
69 | }
70 | 


--------------------------------------------------------------------------------
/src/Signature.ts:
--------------------------------------------------------------------------------
  1 | import { BNInput, ec as EC } from 'elliptic';
  2 | import BN = require('bn.js');
  3 | 
  4 | import {
  5 |     Key,
  6 |     KeyType,
  7 |     signatureToString,
  8 |     stringToSignature,
  9 | } from './eosjs-numeric';
 10 | import { constructElliptic, PublicKey } from './eosjs-key-conversions';
 11 | 
 12 | /** Represents/stores a Signature and provides easy conversion for use with `elliptic` lib */
 13 | export class Signature {
 14 |     constructor(private signature: Key, private ec: EC) {}
 15 | 
 16 |     /** Instantiate Signature from an EOSIO-format Signature */
 17 |     public static fromString(sig: string, ec?: EC): Signature {
 18 |         const signature = stringToSignature(sig);
 19 |         if (!ec) {
 20 |             ec = constructElliptic(signature.type);
 21 |         }
 22 |         return new Signature(signature, ec);
 23 |     }
 24 | 
 25 |     /** Instantiate Signature from an `elliptic`-format Signature */
 26 |     public static fromElliptic(ellipticSig: EC.Signature, keyType: KeyType, ec?: EC): Signature {
 27 |         const r = ellipticSig.r.toArray('be', 32);
 28 |         const s = ellipticSig.s.toArray('be', 32);
 29 |         let eosioRecoveryParam;
 30 |         if (keyType === KeyType.k1 || keyType === KeyType.r1) {
 31 |             eosioRecoveryParam = ellipticSig.recoveryParam + 27;
 32 |             if (ellipticSig.recoveryParam <= 3) {
 33 |                 eosioRecoveryParam += 4;
 34 |             }
 35 |         } else if (keyType === KeyType.wa) {
 36 |             eosioRecoveryParam = ellipticSig.recoveryParam;
 37 |         }
 38 |         const sigData = new Uint8Array([eosioRecoveryParam].concat(r, s));
 39 |         if (!ec) {
 40 |             ec = constructElliptic(keyType);
 41 |         }
 42 |         return new Signature({
 43 |             type: keyType,
 44 |             data: sigData,
 45 |         }, ec);
 46 |     }
 47 | 
 48 |     /** Export Signature as `elliptic`-format Signature
 49 |      * NOTE: This isn't an actual elliptic-format Signature, as ec.Signature is not exported by the library.
 50 |      * That's also why the return type is `any`.  We're *actually* returning an object with the 3 params
 51 |      * not an ec.Signature.
 52 |      * Further NOTE: @types/elliptic shows ec.Signature as exported; it is *not*.  Hence the `any`.
 53 |      */
 54 |     public toElliptic(): any {
 55 |         const lengthOfR = 32;
 56 |         const lengthOfS = 32;
 57 |         const r = new BN(this.signature.data.slice(1, lengthOfR + 1));
 58 |         const s = new BN(this.signature.data.slice(lengthOfR + 1, lengthOfR + lengthOfS + 1));
 59 | 
 60 |         let ellipticRecoveryBitField;
 61 |         if (this.signature.type === KeyType.k1 || this.signature.type === KeyType.r1) {
 62 |             ellipticRecoveryBitField = this.signature.data[0] - 27;
 63 |             if (ellipticRecoveryBitField > 3) {
 64 |                 ellipticRecoveryBitField -= 4;
 65 |             }
 66 |         } else if (this.signature.type === KeyType.wa) {
 67 |             ellipticRecoveryBitField = this.signature.data[0];
 68 |         }
 69 |         const recoveryParam = ellipticRecoveryBitField & 3;
 70 |         return { r, s, recoveryParam };
 71 |     }
 72 | 
 73 |     /** Export Signature as EOSIO-format Signature */
 74 |     public toString(): string {
 75 |         return signatureToString(this.signature);
 76 |     }
 77 | 
 78 |     /** Export Signature in binary format */
 79 |     public toBinary(): Uint8Array {
 80 |         return this.signature.data;
 81 |     }
 82 | 
 83 |     /** Get key type from signature */
 84 |     public getType(): KeyType {
 85 |         return this.signature.type;
 86 |     }
 87 | 
 88 |     /** Verify a signature with a message or hashed message digest and public key */
 89 |     public verify(data: BNInput, publicKey: PublicKey, shouldHash: boolean = true, encoding: BufferEncoding = 'utf8'): boolean {
 90 |         if (shouldHash) {
 91 |             if (typeof data === 'string') {
 92 |                 data = Buffer.from(data, encoding);
 93 |             }
 94 |             data = this.ec.hash().update(data).digest();
 95 |         }
 96 |         const ellipticSignature = this.toElliptic();
 97 |         const ellipticPublicKey = publicKey.toElliptic();
 98 |         return this.ec.verify(data, ellipticSignature, ellipticPublicKey, encoding);
 99 |     }
100 | 
101 |     /** Recover a public key from a message or hashed message digest and signature */
102 |     public recover(data: BNInput, shouldHash: boolean = true, encoding: BufferEncoding = 'utf8'): PublicKey {
103 |         if (shouldHash) {
104 |             if (typeof data === 'string') {
105 |                 data = Buffer.from(data, encoding);
106 |             }
107 |             data = this.ec.hash().update(data).digest();
108 |         }
109 |         const ellipticSignature = this.toElliptic();
110 |         const recoveredPublicKey = this.ec.recoverPubKey(
111 |             data,
112 |             ellipticSignature,
113 |             ellipticSignature.recoveryParam,
114 |             encoding
115 |         );
116 |         const ellipticKPub = this.ec.keyFromPublic(recoveredPublicKey);
117 |         return PublicKey.fromElliptic(ellipticKPub, this.getType(), this.ec);
118 |     }
119 | }
120 | 


--------------------------------------------------------------------------------
/src/eosjs-api-interfaces.ts:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * @module Javascript-API
  3 |  * copyright defined in eosjs/LICENSE.txt
  4 |  */
  5 | 
  6 | import { Abi, PushTransactionArgs, ProcessedAction } from './eosjs-rpc-interfaces';
  7 | import { Anyvar, Authorization, Action, SerializedAction } from './eosjs-serialize';
  8 | 
  9 | /** Arguments to `getRequiredKeys` */
 10 | export interface AuthorityProviderArgs {
 11 |     /** Transaction that needs to be signed */
 12 |     transaction: any;
 13 | 
 14 |     /** Public keys associated with the private keys that the `SignatureProvider` holds */
 15 |     availableKeys: string[];
 16 | }
 17 | 
 18 | /** Get subset of `availableKeys` needed to meet authorities in `transaction` */
 19 | export interface AuthorityProvider {
 20 |     /** Get subset of `availableKeys` needed to meet authorities in `transaction` */
 21 |     getRequiredKeys: (args: AuthorityProviderArgs) => Promise;
 22 | }
 23 | 
 24 | /** Retrieves raw ABIs for a specified accountName */
 25 | export interface AbiProvider {
 26 |     /** Retrieve the BinaryAbi */
 27 |     getRawAbi: (accountName: string) => Promise;
 28 | }
 29 | 
 30 | /** Structure for the raw form of ABIs */
 31 | export interface BinaryAbi {
 32 |     /** account which has deployed the ABI */
 33 |     accountName: string;
 34 | 
 35 |     /** abi in binary form */
 36 |     abi: Uint8Array;
 37 | }
 38 | 
 39 | /** Holds a fetched abi */
 40 | export interface CachedAbi {
 41 |     /** abi in binary form */
 42 |     rawAbi: Uint8Array;
 43 | 
 44 |     /** abi in structured form */
 45 |     abi: Abi;
 46 | }
 47 | 
 48 | /** Arguments to `sign` */
 49 | export interface SignatureProviderArgs {
 50 |     /** Chain transaction is for */
 51 |     chainId: string;
 52 | 
 53 |     /** Public keys associated with the private keys needed to sign the transaction */
 54 |     requiredKeys: string[];
 55 | 
 56 |     /** Transaction to sign */
 57 |     serializedTransaction: Uint8Array;
 58 | 
 59 |     /** Context-free data to sign */
 60 |     serializedContextFreeData?: Uint8Array;
 61 | 
 62 |     /** ABIs for all contracts with actions included in `serializedTransaction` */
 63 |     abis: BinaryAbi[];
 64 | }
 65 | 
 66 | /** Signs transactions */
 67 | export interface SignatureProvider {
 68 |     /** Public keys associated with the private keys that the `SignatureProvider` holds */
 69 |     getAvailableKeys: () => Promise;
 70 | 
 71 |     /** Sign a transaction */
 72 |     sign: (args: SignatureProviderArgs) => Promise;
 73 | }
 74 | 
 75 | export interface ResourcePayer {
 76 |     payer: string;
 77 |     max_net_bytes: number;
 78 |     max_cpu_us: number;
 79 |     max_memory_bytes: number;
 80 | }
 81 | 
 82 | export interface Transaction {
 83 |     expiration?: string;
 84 |     ref_block_num?: number;
 85 |     ref_block_prefix?: number;
 86 |     max_net_usage_words?: number;
 87 |     max_cpu_usage_ms?: number;
 88 |     delay_sec?: number;
 89 |     context_free_actions?: Action[];
 90 |     context_free_data?: Uint8Array[];
 91 |     actions: Action[];
 92 |     transaction_extensions?: [number, string][];
 93 |     resource_payer?: ResourcePayer;
 94 | }
 95 | 
 96 | /** Optional transact configuration object */
 97 | export interface TransactConfig {
 98 |     broadcast?: boolean;
 99 |     sign?: boolean;
100 |     readOnlyTrx?: boolean;
101 |     returnFailureTraces?: boolean;
102 |     requiredKeys?: string[];
103 |     compression?: boolean;
104 |     blocksBehind?: number;
105 |     useLastIrreversible?: boolean;
106 |     expireSeconds?: number;
107 | }
108 | 
109 | export interface TransactionHeader {
110 |     expiration: string;
111 |     ref_block_num: number;
112 |     ref_block_prefix: number;
113 | }
114 | 
115 | export interface AccountDelta {
116 |     account: string;
117 |     delta: number;
118 | }
119 | 
120 | export interface AuthSequence {
121 |     account: string;
122 |     sequence: number;
123 | }
124 | 
125 | export interface ActionReceipt {
126 |     receiver: string;
127 |     act_digest: string;
128 |     global_sequence: number;
129 |     recv_sequence: number;
130 |     auth_sequence: [ string, number ][];
131 |     code_sequence: number;
132 |     abi_sequence: number;
133 | }
134 | 
135 | export interface ActionTrace {
136 |     action_ordinal: number;
137 |     creator_action_ordinal: number;
138 |     closest_unnotified_ancestor_action_ordinal: number;
139 |     receipt: ActionReceipt;
140 |     receiver: string;
141 |     act: ProcessedAction;
142 |     context_free: boolean;
143 |     elapsed: number;
144 |     console: string;
145 |     trx_id: string;
146 |     block_num: number;
147 |     block_time: string;
148 |     producer_block_id: string|null;
149 |     account_ram_deltas: AccountDelta[];
150 |     account_disk_deltas: AccountDelta[];
151 |     except: any;
152 |     error_code: number|null;
153 |     return_value?: any;
154 |     return_value_hex_data?: string;
155 |     return_value_data?: any;
156 |     inline_traces?: ActionTrace[];
157 | }
158 | 
159 | export interface TransactionReceiptHeader {
160 |     status: string;
161 |     cpu_usage_us: number;
162 |     net_usage_words: number;
163 | }
164 | 
165 | export interface TransactionTrace {
166 |     id: string;
167 |     block_num: number;
168 |     block_time: string;
169 |     producer_block_id: string|null;
170 |     receipt: TransactionReceiptHeader|null;
171 |     elapsed: number;
172 |     net_usage: number;
173 |     scheduled: boolean;
174 |     action_traces: ActionTrace[];
175 |     account_ram_delta: AccountDelta|null;
176 |     except: string|null;
177 |     error_code: number|null;
178 |     bill_to_accounts: string[];
179 | }
180 | 
181 | export interface TransactResult {
182 |     transaction_id: string;
183 |     processed: TransactionTrace;
184 | }
185 | 
186 | /** Optional query configuration object */
187 | export interface QueryConfig {
188 |     sign?: boolean;
189 |     requiredKeys?: string[];
190 |     authorization?: Authorization[];
191 | }
192 | 
193 | /**
194 |  * A Query may be any of the following:
195 |  * * string:                                           method
196 |  * * [string, Query[]]:                                [method, filter]
197 |  * * [string, Anyvar, Query[]]:                        [method, arg, filter]
198 |  * * {method: string, arg?: Anyvar, filter?: Query[]}  explicit form
199 |  */
200 | export type Query =
201 |    string | [string, Query[]] | [string, Anyvar, Query[]] | { method: string, arg?: Anyvar, filter?: Query[] };
202 | 
203 | export type ContextFreeGroupCallback =
204 |     (index: {cfa: number, cfd: number}) => {
205 |         action?: SerializedAction;
206 |         contextFreeAction?: SerializedAction;
207 |         contextFreeData?: Uint8Array;
208 |     };
209 | 
210 | export interface ActionSerializerType {
211 |     [actionName: string]: any;
212 | };
213 | 


--------------------------------------------------------------------------------
/src/eosjs-ecc-migration.ts:
--------------------------------------------------------------------------------
 1 | import {PrivateKey, PublicKey, Signature} from './eosjs-jssig';
 2 | import {generateKeyPair} from './eosjs-key-conversions';
 3 | import {KeyType} from './eosjs-numeric';
 4 | import {ec as EC} from 'elliptic';
 5 | 
 6 | export const ecc = {
 7 |     initialize: (): void => console.error('Method deprecated'),
 8 |     unsafeRandomKey: (): void => console.error('Method deprecated'),
 9 |     randomKey: (
10 |         cpuEntropyBits?: number, options: { secureEnv?: boolean, ecOptions?: EC.GenKeyPairOptions } = {}
11 |     ): Promise => {
12 |         if (cpuEntropyBits !== undefined) {
13 |             console.warn('Argument `cpuEntropyBits` is deprecated, ' +
14 |                 'use the options argument instead');
15 |         }
16 | 
17 |         const { privateKey } = generateKeyPair(KeyType.k1, options);
18 |         return Promise.resolve(privateKey.toLegacyString());
19 |     },
20 |     seedPrivate: (): void => console.error('Method deprecated'),
21 |     privateToPublic: (key: string, pubkey_prefix?: string): string => {
22 |         if (pubkey_prefix !== undefined) {
23 |             console.warn('Argument `pubkey_prefix` is deprecated, ' +
24 |                 'keys prefixed with PUB_K1_/PUB_R1_/PUB_WA_ going forward');
25 |         }
26 | 
27 |         const privateKey = PrivateKey.fromString(key);
28 |         const publicKey = privateKey.getPublicKey();
29 |         return publicKey.toLegacyString();
30 |     },
31 |     isValidPublic: (pubkey: string, pubkey_prefix?: string): boolean => {
32 |         if (pubkey_prefix !== undefined) {
33 |             console.warn('Argument `pubkey_prefix` is deprecated, ' +
34 |                 'keys prefixed with PUB_K1_/PUB_R1_/PUB_WA_ going forward');
35 |         }
36 | 
37 |         try {
38 |             const publicKey = PublicKey.fromString(pubkey);
39 |             return publicKey.isValid();
40 |         } catch {
41 |             return false;
42 |         }
43 |     },
44 |     isValidPrivate: (wif: string): boolean => {
45 |         try {
46 |             const privateKey = PrivateKey.fromString(wif);
47 |             return privateKey.isValid();
48 |         } catch {
49 |             return false;
50 |         }
51 |     },
52 |     sign: (data: string|Buffer, privateKey: string|PrivateKey, encoding: BufferEncoding = 'utf8'): string => {
53 |         const privKey = typeof privateKey === 'string' ? PrivateKey.fromString(privateKey) : privateKey;
54 |         const signature = privKey.sign(data, true, encoding);
55 |         return signature.toString();
56 |     },
57 |     signHash: (dataSha256: string|Buffer, privateKey: string|PrivateKey, encoding: BufferEncoding = 'hex'): string => {
58 |         const privKey = typeof privateKey === 'string' ? PrivateKey.fromString(privateKey) : privateKey;
59 |         const signature = privKey.sign(dataSha256, false, encoding);
60 |         return signature.toString();
61 |     },
62 |     verify: (
63 |         signature: string, data: string, pubKey: string|PublicKey, encoding: BufferEncoding = 'utf8', hashData: boolean = true
64 |     ): boolean => {
65 |         const publicKey = typeof pubKey === 'string' ? PublicKey.fromString(pubKey) : pubKey;
66 |         const sig = Signature.fromString(signature);
67 |         return sig.verify(data, publicKey, hashData, encoding);
68 |     },
69 |     recover: (signature: string, data: string, encoding: BufferEncoding = 'utf8'): string => {
70 |         const sig = Signature.fromString(signature);
71 |         const publicKey = sig.recover(data, true, encoding);
72 |         return publicKey.toLegacyString();
73 |     },
74 |     recoverHash: (signature: string, dataSha256: string|Buffer, encoding: BufferEncoding = 'hex'): string => {
75 |         const sig = Signature.fromString(signature);
76 |         const publicKey = sig.recover(dataSha256, false, encoding);
77 |         return publicKey.toLegacyString();
78 |     },
79 |     sha256: (data: string|Buffer, resultEncoding?: string, encoding?: string): string|Buffer => {
80 |         if (encoding !== undefined) {
81 |             console.warn('Argument `encoding` is deprecated');
82 |         }
83 |         if (resultEncoding !== undefined) {
84 |             console.warn('Argument `resultEncoding` is deprecated');
85 |         }
86 | 
87 |         return require('./eosjs-key-conversions').sha256(data);
88 |     }
89 | };
90 | 


--------------------------------------------------------------------------------
/src/eosjs-jssig.ts:
--------------------------------------------------------------------------------
 1 | /**
 2 |  * @module JS-Sig
 3 |  */
 4 | // copyright defined in eosjs/LICENSE.txt
 5 | 
 6 | import { ec } from 'elliptic';
 7 | 
 8 | import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces';
 9 | import { PushTransactionArgs } from './eosjs-rpc-interfaces';
10 | import {
11 |     PrivateKey,
12 |     PublicKey,
13 |     Signature,
14 | } from './eosjs-key-conversions';
15 | import { convertLegacyPublicKey } from './eosjs-numeric';
16 | 
17 | /** expensive to construct; so we do it once and reuse it */
18 | const defaultEc = new ec('secp256k1');
19 | 
20 | /** Construct the digest from transaction details */
21 | const digestFromSerializedData = (
22 |     chainId: string,
23 |     serializedTransaction: Uint8Array,
24 |     serializedContextFreeData?: Uint8Array,
25 |     e = defaultEc): string => {
26 |     const signBuf = Buffer.concat([
27 |         Buffer.from(chainId, 'hex'),
28 |         Buffer.from(serializedTransaction),
29 |         Buffer.from(
30 |             serializedContextFreeData ?
31 |                 new Uint8Array(e.hash().update(serializedContextFreeData).digest()) :
32 |                 new Uint8Array(32)
33 |         ),
34 |     ]);
35 |     return e.hash().update(signBuf).digest();
36 | };
37 | 
38 | /** Signs transactions using in-process private keys */
39 | class JsSignatureProvider implements SignatureProvider {
40 |     /** map public to private keys */
41 |     public keys = new Map();
42 | 
43 |     /** public keys */
44 |     public availableKeys = [] as string[];
45 | 
46 |     /** @param privateKeys private keys to sign with */
47 |     constructor(privateKeys: string[]) {
48 |         for (const k of privateKeys) {
49 |             const priv = PrivateKey.fromString(k);
50 |             const privElliptic = priv.toElliptic();
51 |             const pubStr = priv.getPublicKey().toString();
52 |             this.keys.set(pubStr, privElliptic);
53 |             this.availableKeys.push(pubStr);
54 |         }
55 |     }
56 | 
57 |     /** Public keys associated with the private keys that the `SignatureProvider` holds */
58 |     public async getAvailableKeys(): Promise {
59 |         return this.availableKeys;
60 |     }
61 | 
62 |     /** Sign a transaction */
63 |     public async sign(
64 |         { chainId, requiredKeys, serializedTransaction, serializedContextFreeData }: SignatureProviderArgs,
65 |     ): Promise {
66 |         const digest = digestFromSerializedData( chainId, serializedTransaction, serializedContextFreeData, defaultEc);
67 | 
68 |         const signatures = [] as string[];
69 |         for (const key of requiredKeys) {
70 |             const publicKey = PublicKey.fromString(key);
71 |             const ellipticPrivateKey = this.keys.get(convertLegacyPublicKey(key));
72 |             const privateKey = PrivateKey.fromElliptic(ellipticPrivateKey, publicKey.getType());
73 |             const signature = privateKey.sign(digest, false);
74 |             signatures.push(signature.toString());
75 |         }
76 | 
77 |         return { signatures, serializedTransaction, serializedContextFreeData };
78 |     }
79 | }
80 | 
81 | export {
82 |     PrivateKey,
83 |     PublicKey,
84 |     Signature,
85 |     digestFromSerializedData,
86 |     JsSignatureProvider,
87 | };
88 | 


--------------------------------------------------------------------------------
/src/eosjs-key-conversions.ts:
--------------------------------------------------------------------------------
 1 | import {ec as EC} from 'elliptic';
 2 | import * as hash from 'hash.js';
 3 | import {KeyType} from './eosjs-numeric';
 4 | import { PublicKey } from './PublicKey';
 5 | import { PrivateKey } from './PrivateKey';
 6 | 
 7 | export { PrivateKey } from './PrivateKey';
 8 | export { PublicKey } from './PublicKey';
 9 | export { Signature } from './Signature';
10 | 
11 | /** Construct the elliptic curve object based on key type */
12 | export const constructElliptic = (type: KeyType): EC => {
13 |     if (type === KeyType.k1) {
14 |         return new EC('secp256k1');
15 |     }
16 |     return new EC('p256');
17 | };
18 | 
19 | export const generateKeyPair = (
20 |     type: KeyType, options: { secureEnv?: boolean, ecOptions?: EC.GenKeyPairOptions } = {}
21 | ): { publicKey: PublicKey, privateKey: PrivateKey } => {
22 |     if (!options.secureEnv) {
23 |         throw new Error('Key generation is completely INSECURE in production environments in the browser. ' +
24 |             'If you are absolutely certain this does NOT describe your environment, set `secureEnv` in your ' +
25 |             'options to `true`.  If this does describe your environment and you set `secureEnv` to `true`, ' +
26 |             'YOU DO SO AT YOUR OWN RISK AND THE RISK OF YOUR USERS.');
27 |     }
28 |     let ec;
29 |     if (type === KeyType.k1) {
30 |         ec = new EC('secp256k1');
31 |     } else {
32 |         ec = new EC('p256');
33 |     }
34 |     const ellipticKeyPair = ec.genKeyPair(options.ecOptions);
35 |     const publicKey = PublicKey.fromElliptic(ellipticKeyPair, type, ec);
36 |     const privateKey = PrivateKey.fromElliptic(ellipticKeyPair, type, ec);
37 |     return {publicKey, privateKey};
38 | };
39 | 
40 | export const sha256 = (data: string|Buffer): number[]|string => {
41 |     return hash.sha256().update(data).digest();
42 | };
43 | 


--------------------------------------------------------------------------------
/src/eosjs-rpcerror.ts:
--------------------------------------------------------------------------------
 1 | /**
 2 |  * @module RPC-Error
 3 |  */
 4 | // copyright defined in eosjs/LICENSE.txt
 5 | 
 6 | /** Holds detailed error information */
 7 | export class RpcError extends Error {
 8 |     /** Detailed error information */
 9 |     public json: any;
10 |     public details: any;
11 | 
12 |     constructor(json: any) {
13 |         if (json.error && json.error.details && json.error.details.length && json.error.details[0].message) {
14 |             super(json.error.details[0].message);
15 |             this.details = json.error.details;
16 |         } else if (json.processed && json.processed.except && json.processed.except.message) {
17 |             super(json.processed.except.message);
18 |             this.details = json.processed.except;
19 |         } else if (json.result && json.result.except && json.result.except.message) {
20 |             super(json.result.except.message);
21 |             this.details = json.result.except;
22 |         } else {
23 |             super(json.message);
24 |         }
25 |         Object.setPrototypeOf(this, RpcError.prototype);
26 |         this.json = json;
27 |     }
28 | }
29 | 


--------------------------------------------------------------------------------
/src/eosjs-webauthn-sig.ts:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * @module WebAuthn-Sig
  3 |  */
  4 | // copyright defined in eosjs/LICENSE.txt
  5 | 
  6 | import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces';
  7 | import { PushTransactionArgs } from './eosjs-rpc-interfaces';
  8 | import * as ser from './eosjs-serialize';
  9 | import * as numeric from './eosjs-numeric';
 10 | import { ec } from 'elliptic';
 11 | 
 12 | /** Signs transactions using WebAuthn */
 13 | export class WebAuthnSignatureProvider implements SignatureProvider {
 14 |     /** Map public key to credential ID (hex). User must populate this. */
 15 |     public keys = new Map();
 16 | 
 17 |     /** Public keys that the `SignatureProvider` holds */
 18 |     public async getAvailableKeys(): Promise {
 19 |         return Array.from(this.keys.keys());
 20 |     }
 21 | 
 22 |     /** Sign a transaction */
 23 |     public async sign(
 24 |         { chainId, requiredKeys, serializedTransaction, serializedContextFreeData }: SignatureProviderArgs,
 25 |     ): Promise {
 26 |         const signBuf = new ser.SerialBuffer();
 27 |         signBuf.pushArray(ser.hexToUint8Array(chainId));
 28 |         signBuf.pushArray(serializedTransaction);
 29 |         if (serializedContextFreeData) {
 30 |             signBuf.pushArray(new Uint8Array(await crypto.subtle.digest('SHA-256', serializedContextFreeData.buffer)));
 31 |         } else {
 32 |             signBuf.pushArray(new Uint8Array(32));
 33 |         }
 34 |         const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', signBuf.asUint8Array().slice().buffer));
 35 | 
 36 |         const signatures = [] as string[];
 37 |         for (const key of requiredKeys) {
 38 |             const id = ser.hexToUint8Array(this.keys.get(key));
 39 |             const assertion = await (navigator as any).credentials.get({
 40 |                 publicKey: {
 41 |                     timeout: 60000,
 42 |                     allowCredentials: [{
 43 |                         id,
 44 |                         type: 'public-key',
 45 |                     }],
 46 |                     challenge: digest.buffer,
 47 |                 },
 48 |             });
 49 |             const e = new ec('p256') as any; // https://github.com/indutny/elliptic/pull/232
 50 |             const pubKey = e.keyFromPublic(numeric.stringToPublicKey(key).data.subarray(0, 33)).getPublic();
 51 | 
 52 |             const fixup = (x: Uint8Array): Uint8Array => {
 53 |                 const a = Array.from(x);
 54 |                 while (a.length < 32) {
 55 |                     a.unshift(0);
 56 |                 }
 57 |                 while (a.length > 32) {
 58 |                     if (a.shift() !== 0) {
 59 |                         throw new Error('Signature has an r or s that is too big');
 60 |                     }
 61 |                 }
 62 |                 return new Uint8Array(a);
 63 |             };
 64 | 
 65 |             const der = new ser.SerialBuffer({ array: new Uint8Array(assertion.response.signature) });
 66 |             if (der.get() !== 0x30) {
 67 |                 throw new Error('Signature missing DER prefix');
 68 |             }
 69 |             if (der.get() !== der.array.length - 2) {
 70 |                 throw new Error('Signature has bad length');
 71 |             }
 72 |             if (der.get() !== 0x02) {
 73 |                 throw new Error('Signature has bad r marker');
 74 |             }
 75 |             const r = fixup(der.getUint8Array(der.get()));
 76 |             if (der.get() !== 0x02) {
 77 |                 throw new Error('Signature has bad s marker');
 78 |             }
 79 |             const s = fixup(der.getUint8Array(der.get()));
 80 | 
 81 |             const whatItReallySigned = new ser.SerialBuffer();
 82 |             whatItReallySigned.pushArray(new Uint8Array(assertion.response.authenticatorData));
 83 |             whatItReallySigned.pushArray(new Uint8Array(
 84 |                 await crypto.subtle.digest('SHA-256', assertion.response.clientDataJSON)));
 85 |             const hash = new Uint8Array(
 86 |                 await crypto.subtle.digest('SHA-256', whatItReallySigned.asUint8Array().slice()));
 87 |             const recid = e.getKeyRecoveryParam(hash, new Uint8Array(assertion.response.signature), pubKey);
 88 | 
 89 |             const sigData = new ser.SerialBuffer();
 90 |             sigData.push(recid + 27 + 4);
 91 |             sigData.pushArray(r);
 92 |             sigData.pushArray(s);
 93 |             sigData.pushBytes(new Uint8Array(assertion.response.authenticatorData));
 94 |             sigData.pushBytes(new Uint8Array(assertion.response.clientDataJSON));
 95 | 
 96 |             const sig = numeric.signatureToString({
 97 |                 type: numeric.KeyType.wa,
 98 |                 data: sigData.asUint8Array().slice(),
 99 |             });
100 |             signatures.push(sig);
101 |         }
102 |         return { signatures, serializedTransaction, serializedContextFreeData };
103 |     }
104 | }
105 | 


--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
 1 | import { Api } from './eosjs-api';
 2 | import * as ApiInterfaces from './eosjs-api-interfaces';
 3 | import { JsonRpc } from './eosjs-jsonrpc';
 4 | import * as Numeric from './eosjs-numeric';
 5 | import * as RpcInterfaces from './eosjs-rpc-interfaces';
 6 | import { RpcError } from './eosjs-rpcerror';
 7 | import * as Serialize from './eosjs-serialize';
 8 | 
 9 | export { Api, ApiInterfaces, JsonRpc, Numeric, RpcInterfaces, RpcError, Serialize };
10 | 


--------------------------------------------------------------------------------
/src/rpc-web.ts:
--------------------------------------------------------------------------------
1 | import { JsonRpc } from './eosjs-jsonrpc';
2 | import { RpcError } from './eosjs-rpcerror';
3 | 
4 | export { JsonRpc, RpcError };
5 | 


--------------------------------------------------------------------------------
/src/tests/eosjs-ecc-migration.test.ts:
--------------------------------------------------------------------------------
  1 | const ecc = require('eosjs-ecc');
  2 | import { ecc as eccMigration } from '../eosjs-ecc-migration';
  3 | 
  4 | import { PrivateKey } from '../eosjs-key-conversions';
  5 | 
  6 | describe('ecc Migration', () => {
  7 |     const privateKeys = [
  8 |         '5Juww5SS6aLWxopXBAWzwqrwadiZKz7XpKAiktXTKcfBGi1DWg8',
  9 |         '5JnHjSFwe4r7xyqAUAaVs51G7HmzE86DWGa3VAA5VvQriGYnSUr',
 10 |         '5K4XZH5XR2By7Q5KTcZnPAmUMU5yjUNBdoKzzXyrLfmiEZJqoKE',
 11 |     ];
 12 |     const legacyPublicKeys = [
 13 |         'EOS7tgwU6E7pAUQJgqEJt66Yi8cWvanTUW8ZfBjeXeJBQvhTU9ypi',
 14 |         'EOS8VaY5CiTexYqgQZyPTJkc3qvWuZUi12QrZL9ssjqW2es6aQk2F',
 15 |         'EOS7VGhqctkKprW1VUj19DZZiiZLX3YcJqUJCuEcahJmUCw3wJEMu',
 16 |     ];
 17 | 
 18 |     it('verifies `initialize` returns console.error message', () => {
 19 |         console.error = jest.fn();
 20 |         eccMigration.initialize();
 21 |         expect(console.error).toHaveBeenCalledWith('Method deprecated');
 22 |     });
 23 | 
 24 |     it('verifies `unsafeRandomKey` returns console.error message', () => {
 25 |         console.error = jest.fn();
 26 |         eccMigration.unsafeRandomKey();
 27 |         expect(console.error).toHaveBeenCalledWith('Method deprecated');
 28 |     });
 29 | 
 30 |     it('verifies `randomKey` calls generateKeyPair', async () => {
 31 |         console.warn = jest.fn();
 32 |         const privateKey = await eccMigration.randomKey(0, { secureEnv: true });
 33 |         expect(console.warn).toHaveBeenCalledWith('Argument `cpuEntropyBits` is deprecated, ' +
 34 |             'use the options argument instead');
 35 |         expect(typeof privateKey).toEqual('string');
 36 |         expect(PrivateKey.fromString(privateKey).isValid()).toBeTruthy();
 37 |     });
 38 | 
 39 |     it('verifies `seedPrivate` returns console.error message', () => {
 40 |         console.error = jest.fn();
 41 |         eccMigration.seedPrivate();
 42 |         expect(console.error).toHaveBeenCalledWith('Method deprecated');
 43 |     });
 44 | 
 45 |     it('verifies `privateToPublic` function is consistent between ecc objects', () => {
 46 |         console.warn = jest.fn();
 47 |         const eccPublicKey = ecc.privateToPublic(privateKeys[0], 'EOS');
 48 |         const eccMigrationPublicKey = eccMigration.privateToPublic(privateKeys[0], 'EOS');
 49 |         expect(console.warn).toHaveBeenCalledWith('Argument `pubkey_prefix` is deprecated, ' +
 50 |             'keys prefixed with PUB_K1_/PUB_R1_/PUB_WA_ going forward');
 51 |         expect(eccPublicKey).toEqual(eccMigrationPublicKey);
 52 |     });
 53 | 
 54 |     it('verifies `isValidPublic` function is consistent between ecc objects', () => {
 55 |         console.warn = jest.fn();
 56 |         const eccValid = ecc.isValidPublic(legacyPublicKeys[0], 'EOS');
 57 |         const eccMigrationValid = eccMigration.isValidPublic(legacyPublicKeys[0], 'EOS');
 58 |         expect(console.warn).toHaveBeenCalledWith('Argument `pubkey_prefix` is deprecated, ' +
 59 |             'keys prefixed with PUB_K1_/PUB_R1_/PUB_WA_ going forward');
 60 |         expect(eccValid).toEqual(eccMigrationValid);
 61 |         expect(eccValid).toBeTruthy();
 62 |         expect(eccMigrationValid).toBeTruthy();
 63 |     });
 64 | 
 65 |     it('verifies `isValidPublic` function is consistent during an error', () => {
 66 |         console.warn = jest.fn();
 67 |         const eccValid = ecc.isValidPublic('publickey', 'EOS');
 68 |         const eccMigrationValid = eccMigration.isValidPublic('publickey', 'EOS');
 69 |         expect(console.warn).toHaveBeenCalledWith('Argument `pubkey_prefix` is deprecated, ' +
 70 |             'keys prefixed with PUB_K1_/PUB_R1_/PUB_WA_ going forward');
 71 |         expect(eccValid).toEqual(eccMigrationValid);
 72 |         expect(eccValid).toBeFalsy();
 73 |         expect(eccMigrationValid).toBeFalsy();
 74 |     });
 75 | 
 76 |     it('verifies `isValidPrivate` function is consistent between ecc objects', () => {
 77 |         const eccValid = ecc.isValidPrivate(privateKeys[0]);
 78 |         const eccMigrationValid = eccMigration.isValidPrivate(privateKeys[0]);
 79 |         expect(eccValid).toEqual(eccMigrationValid);
 80 |         expect(eccValid).toBeTruthy();
 81 |         expect(eccMigrationValid).toBeTruthy();
 82 |     });
 83 | 
 84 |     it('verifies `isValidPrivate` function is consistent during an error', () => {
 85 |         const eccValid = ecc.isValidPrivate('privatekey');
 86 |         const eccMigrationValid = eccMigration.isValidPrivate('privatekey');
 87 |         expect(eccValid).toEqual(eccMigrationValid);
 88 |         expect(eccValid).toBeFalsy();
 89 |         expect(eccMigrationValid).toBeFalsy();
 90 |     });
 91 | 
 92 |     it('verifies `sign`, `recover`, and `verify` functions are consistent between ecc objects', () => {
 93 |         const dataAsString = 'some string';
 94 |         const eccSig = ecc.sign(dataAsString, privateKeys[0], 'utf8');
 95 |         const eccMigrationSig = eccMigration.sign(dataAsString, privateKeys[0], 'utf8');
 96 | 
 97 |         // signatures are different
 98 |         expect(eccSig).not.toEqual(eccMigrationSig);
 99 | 
100 |         const eccKPub = ecc.recover(eccSig, dataAsString, 'utf8');
101 |         const eccMigrationKPub = eccMigration.recover(eccMigrationSig, dataAsString, 'utf8');
102 |         expect(eccKPub).toEqual(eccMigrationKPub);
103 |     });
104 | 
105 |     it('verifies `signHash`, `recoverHash`, and `sha256` functions are consistent between ecc objects', () => {
106 |         console.warn = jest.fn();
107 |         const dataAsString = 'some string';
108 | 
109 |         const eccHash = Buffer.from(ecc.sha256(dataAsString), 'hex');
110 |         const eccMigrationHash = Buffer.from(eccMigration.sha256(dataAsString, 'hex', 'utf8') as string, 'hex');
111 |         expect(console.warn).toBeCalledWith('Argument `encoding` is deprecated');
112 |         expect(console.warn).toBeCalledWith('Argument `resultEncoding` is deprecated');
113 |         expect(eccHash).toEqual(eccMigrationHash);
114 | 
115 |         const eccSig = ecc.signHash(eccHash, privateKeys[0], 'utf8');
116 |         const eccMigrationSig = eccMigration.signHash(eccMigrationHash, privateKeys[0], 'utf8');
117 | 
118 |         // signatures are different
119 |         expect(eccSig).not.toEqual(eccMigrationSig);
120 | 
121 |         const eccKPub = ecc.recoverHash(eccSig, eccHash, 'utf8');
122 |         const eccMigrationKPub = eccMigration.recoverHash(eccSig, eccMigrationHash, 'utf8');
123 |         expect(eccKPub).toEqual(eccMigrationKPub);
124 |     });
125 | });
126 | 


--------------------------------------------------------------------------------
/src/tests/eosjs-ecc-verification.test.js:
--------------------------------------------------------------------------------
  1 | // eosjs-ecc stuff
  2 | const ecc = require('eosjs-ecc');
  3 | 
  4 | const { ec } = require('elliptic');
  5 | 
  6 | const { Signature, PrivateKey, PublicKey, sha256 } = require('../eosjs-key-conversions');
  7 | const {
  8 |     JsSignatureProvider,
  9 | } = require('../eosjs-jssig');
 10 | const { KeyType } = require('../eosjs-numeric');
 11 | const { SignatureProviderArgs } = require('../eosjs-api-interfaces');
 12 | 
 13 | describe('JsSignatureProvider', () => {
 14 |     const privateKeys = [
 15 |         '5Juww5SS6aLWxopXBAWzwqrwadiZKz7XpKAiktXTKcfBGi1DWg8',
 16 |         '5JnHjSFwe4r7xyqAUAaVs51G7HmzE86DWGa3VAA5VvQriGYnSUr',
 17 |         '5K4XZH5XR2By7Q5KTcZnPAmUMU5yjUNBdoKzzXyrLfmiEZJqoKE',
 18 |     ];
 19 |     const legacyPublicKeys = [
 20 |         'EOS7tgwU6E7pAUQJgqEJt66Yi8cWvanTUW8ZfBjeXeJBQvhTU9ypi',
 21 |         'EOS8VaY5CiTexYqgQZyPTJkc3qvWuZUi12QrZL9ssjqW2es6aQk2F',
 22 |         'EOS7VGhqctkKprW1VUj19DZZiiZLX3YcJqUJCuEcahJmUCw3wJEMu',
 23 |     ];
 24 |     const k1FormatPublicKeys = [
 25 |         'PUB_K1_7tgwU6E7pAUQJgqEJt66Yi8cWvanTUW8ZfBjeXeJBQvhYTBFvY',
 26 |         'PUB_K1_8VaY5CiTexYqgQZyPTJkc3qvWuZUi12QrZL9ssjqW2es7e7bRJ',
 27 |         'PUB_K1_7VGhqctkKprW1VUj19DZZiiZLX3YcJqUJCuEcahJmUCw9RT8v2',
 28 |     ];
 29 |     const signatures = [
 30 |         'SIG_K1_HKkqi3zray76i63ZQwAHWMjoLk3wTa1ajZWPcUnrhgmSWQYEHDJsxkny6VDTWEmVdfktxpGoTA81qe6QuCrDmazeQndmxh',
 31 |         'SIG_K1_HCaY9Y9qdjnkRhE9hokAyp3pFtkMmjpxF6xTd514Vo8vLVSWKek5m5aHfCaka9TqZUbajkhhd4BfBLxSwCwZUEmy8cvt1x',
 32 |         'SIG_K1_GrZqp9ZkuhBeNpeQ5b2L2UWUUrNU1gHbTyMzkyWRhiXNkxPP84Aq9eziU399eBf9xJw8MqHHjz7R2wMTMXhXjHLgpZYFeA',
 33 |     ];
 34 |     const eccSignatures = [
 35 |         'SIG_K1_KeEyJFpkp63Qq5E1zRD9aNZtTjpStvdkdnL31Z7wVmhYtrKGtpVdMBJnXyEUXNkNEyo4d4i4Q79qmRpCUsCRdFqhV6KAeF',
 36 |         'SIG_K1_JvgMmFSDhipS1SeBLNBMdAxayAsWS3GuVGSHS7YQth5Z5ZpijxnZgaa23dYD1efQhpEgtEggdRfHMmp31RDXjmJdZYoKLm',
 37 |         'SIG_K1_JwMqV2nbEntHSq9AuG3Zq1JBc5YqD2SftMHCTGK4A8DYGn1VPQ8QAduwCNksT5JhYgAmGMzPyJdZ2Ws4p8TCvQ16LeNhrw',
 38 |     ];
 39 | 
 40 |     // These are simplified tests simply to verify a refactor didn't mess with existing code
 41 | 
 42 |     it('(NOTE: sigs are different): ensure elliptic does what eosjs-ecc used to do', () => {
 43 |         const ellipticEc = new ec('secp256k1');
 44 |         for (let idx=0; idx {
 81 |         const ellipticEc = new ec('secp256k1');
 82 |         for (let idx=0; idx {
119 |         const ellipticEc = new ec('secp256k1');
120 |         for (let idx=0; idx {
148 |         for (let idx=0; idx {
173 |         for (let idx=0; idx {
  7 |     let types: Map;
  8 | 
  9 |     beforeAll(() => {
 10 |         types = createInitialTypes();
 11 |     });
 12 | 
 13 |     it('should be able to createInitialTypes', () => {
 14 |         expect(types).toBeTruthy();
 15 |     });
 16 | 
 17 |     describe('pushAsset', () => {
 18 |         let serialBuffer: SerialBuffer;
 19 |         const genericValidSymbolCharacter = 'A';
 20 |         const invalidSymbolErrorMessage = 'Expected symbol to be A-Z and between one and seven characters';
 21 | 
 22 |         beforeEach(() => {
 23 |             serialBuffer = new SerialBuffer({
 24 |                 textEncoder: new TextEncoder(),
 25 |                 textDecoder: new TextDecoder()
 26 |             });
 27 |         });
 28 | 
 29 |         const expectSuccessForICharactersSymbol = (i: number) => {
 30 |             const symbol = genericValidSymbolCharacter.repeat(i);
 31 |             const asset = `10.000 ${symbol}`;
 32 | 
 33 |             serialBuffer.pushAsset(asset);
 34 | 
 35 |             expect(serialBuffer.length).not.toBe(0);
 36 |         };
 37 | 
 38 |         const expectExceptionThrown = (asset: string) => {
 39 |             let exceptionCaught = false;
 40 | 
 41 |             try {
 42 |                 serialBuffer.pushAsset(asset);
 43 |             } catch (e) {
 44 |                 expect(e.message).toBe(invalidSymbolErrorMessage);
 45 |                 exceptionCaught = true;
 46 |             }
 47 | 
 48 |             expect(exceptionCaught).toBeTruthy();
 49 |         };
 50 | 
 51 |         for (let i = 1; i <= 7; i++) {
 52 |             it(`should be able to push asset with valid symbol of ${i} character(s)`, () => {
 53 |                 expectSuccessForICharactersSymbol(i);
 54 |             });
 55 |         }
 56 | 
 57 |         it('should be able to push asset with valid EOS symbol "10.000 EOS"', () => {
 58 |             const asset = '10.000 EOS';
 59 | 
 60 |             serialBuffer.pushAsset(asset);
 61 | 
 62 |             expect(serialBuffer.length).not.toBe(0);
 63 |         });
 64 | 
 65 |         it('should not be able to push no symbol "10.000 "', () => {
 66 |             const asset = '10.000 ';
 67 | 
 68 |             expectExceptionThrown(asset);
 69 |         });
 70 | 
 71 |         it('should not be able to push symbol with 8 or more characters "10.000 AAAAAAAA"', () => {
 72 |             const asset = '10.000 AAAAAAAA';
 73 | 
 74 |             expectExceptionThrown(asset);
 75 |         });
 76 | 
 77 |         it('should not be able to push invalid lowercase symbol "10.000 eos"', () => {
 78 |             const asset = '10.000 eos';
 79 | 
 80 |             expectExceptionThrown(asset);
 81 |         });
 82 | 
 83 |         it('should not be able to push two symbols "10.000 EOS blah"', () => {
 84 |             const asset = '10.000 EOS blah';
 85 | 
 86 |             expectExceptionThrown(asset);
 87 |         });
 88 |     });
 89 | 
 90 |     describe('name', () => {
 91 |         let serialBuffer: SerialBuffer;
 92 |         const invalidNameErrorMessage = 'Name should be less than 13 characters, or less than 14 if last character is between 1-5 or a-j, and only contain the following symbols .12345abcdefghijklmnopqrstuvwxyz';
 93 | 
 94 |         beforeEach(() => {
 95 |             serialBuffer = new SerialBuffer({
 96 |                 textEncoder: new TextEncoder(),
 97 |                 textDecoder: new TextDecoder()
 98 |             });
 99 |         });
100 | 
101 |         it('should be able to push name with a valid account name', () => {
102 |             const name = '.12345abcdefg';
103 | 
104 |             serialBuffer.pushName(name);
105 | 
106 |             expect(serialBuffer.getName()).toEqual(name);
107 |         });
108 | 
109 |         it('should remove the `.` character from the end of the account name', () => {
110 |             const name = 'abcd......';
111 |             const expectedName = 'abcd';
112 | 
113 |             serialBuffer.pushName(name);
114 |             expect(serialBuffer.getName()).toEqual(expectedName);
115 |         });
116 | 
117 |         it('should not be able to push name with an account name too long', () => {
118 |             const name = 'abcdabcdabcdab';
119 | 
120 |             const shouldFail = () => serialBuffer.pushName(name);
121 |             expect(shouldFail).toThrowError(invalidNameErrorMessage);
122 |         });
123 | 
124 |         it('should not be able to push name with an account name with invalid characters', () => {
125 |             const name = '6789$/,';
126 | 
127 |             const shouldFail = () => serialBuffer.pushName(name);
128 |             expect(shouldFail).toThrowError(invalidNameErrorMessage);
129 |         });
130 |     });
131 | 
132 |     describe('bool', () => {
133 |         let boolType: Type;
134 |         let mockedBuffer: SerialBuffer;
135 | 
136 |         const shouldThrowErrorForValue = (value: any) => {
137 |             try {
138 |                 boolType.serialize(mockedBuffer, value);
139 |             } catch (e) {
140 |                 expect(e.message).toBe('Expected boolean or number equal to 1 or 0');
141 |             }
142 |         };
143 | 
144 |         const shouldNotThrowErrorForValue = (value: any) => {
145 |             expect(() => {
146 |                 boolType.serialize(mockedBuffer, value);
147 |             }).not.toThrow();
148 |         };
149 | 
150 |         beforeAll(() => {
151 |             boolType = types.get('bool');
152 |             mockedBuffer = Object.create(SerialBuffer);
153 |             mockedBuffer.push = jest.fn().mockImplementation((value) => {
154 |                 return;
155 |             });
156 |         });
157 | 
158 |         it('should be able to create bool type', () => {
159 |             expect(boolType).toBeTruthy();
160 |         });
161 | 
162 |         it('should throw error when calling serialize when type is not boolean or number', () => {
163 |             const dataValue = 'string';
164 | 
165 |             shouldThrowErrorForValue(dataValue);
166 |         });
167 | 
168 |         it('should throw error when calling serialize when number that is not 1 or 0', () => {
169 |             const dataValue = 10;
170 | 
171 |             shouldThrowErrorForValue(dataValue);
172 |         });
173 | 
174 |         it('should not throw error when calling serialize with false', () => {
175 |             const dataValue = false;
176 | 
177 |             shouldNotThrowErrorForValue(dataValue);
178 |         });
179 | 
180 |         it('should not throw error when calling serialize with true', () => {
181 |             const dataValue = true;
182 | 
183 |             shouldNotThrowErrorForValue(dataValue);
184 |         });
185 | 
186 |         it('should not throw error when calling serialize with 0', () => {
187 |             const dataValue = 0;
188 | 
189 |             shouldNotThrowErrorForValue(dataValue);
190 |         });
191 | 
192 |         it('should not throw error when calling serialize with 1', () => {
193 |             const dataValue = 1;
194 | 
195 |             shouldNotThrowErrorForValue(dataValue);
196 |         });
197 |     });
198 | });
199 | 


--------------------------------------------------------------------------------
/src/tests/logo.svg:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         
 5 |             
 6 |                 
 7 |                 
 8 |             
 9 |         
10 |     
11 | 
12 | 


--------------------------------------------------------------------------------
/src/tests/node.js:
--------------------------------------------------------------------------------
  1 | const fs = require('fs');
  2 | const path = require('path');
  3 | const { JsonRpc, RpcError, Api } = require('../../dist');
  4 | const { JsSignatureProvider } = require('../../dist/eosjs-jssig');
  5 | const fetch = require('node-fetch');
  6 | const { TextEncoder, TextDecoder } = require('util');
  7 | 
  8 | const privateKey = '5JuH9fCXmU3xbj8nRmhPZaVrxxXrdPaRmZLW1cznNTmTQR2Kg5Z'; // replace with "bob" account private key
  9 | const r1PrivateKey = 'PVT_R1_GrfEfbv5at9kbeHcGagQmvbFLdm6jqEpgE1wsGbrfbZNjpVgT';
 10 | const cfactorPrivateKey = '5K8Sm2bB2b7ZC8tJMefrk1GFa4jgtHxxHRcjX49maMk9AEwq8hN';
 11 | /* new accounts for testing can be created by unlocking a cleos wallet then calling:
 12 |  * 1) cleos create key --to-console (copy this privateKey & publicKey)
 13 |  * 2) cleos wallet import
 14 |  * 3) cleos create account bob publicKey
 15 |  * 4) cleos create account alice publicKey
 16 |  */
 17 | 
 18 | const rpc = new JsonRpc('http://localhost:8888', { fetch });
 19 | const signatureProvider = new JsSignatureProvider([privateKey, r1PrivateKey, cfactorPrivateKey]);
 20 | const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });
 21 | 
 22 | const transactWithConfig = async (config, memo, from = 'bob', to = 'alice') => {
 23 |     return await api.transact({
 24 |         actions: [{
 25 |             account: 'eosio.token',
 26 |             name: 'transfer',
 27 |             authorization: [{
 28 |                 actor: from,
 29 |                 permission: 'active',
 30 |             }],
 31 |             data: {
 32 |                 from,
 33 |                 to,
 34 |                 quantity: '0.0001 SYS',
 35 |                 memo,
 36 |             },
 37 |         }]
 38 |     }, config);
 39 | };
 40 | 
 41 | const transactWithoutConfig = async () => {
 42 |     const transactionResponse = await transactWithConfig({ blocksBehind: 3, expireSeconds: 30}, 'transactWithoutConfig');
 43 |     const blockInfo = await rpc.get_block_info(transactionResponse.processed.block_num - 3);
 44 |     const currentDate = new Date();
 45 |     const timePlusTen = currentDate.getTime() + 10000;
 46 |     const timeInISOString = (new Date(timePlusTen)).toISOString();
 47 |     const expiration = timeInISOString.substr(0, timeInISOString.length - 1);
 48 | 
 49 |     return await api.transact({
 50 |         expiration,
 51 |         ref_block_num: blockInfo.block_num & 0xffff,
 52 |         ref_block_prefix: blockInfo.ref_block_prefix,
 53 |         actions: [{
 54 |             account: 'eosio.token',
 55 |             name: 'transfer',
 56 |             authorization: [{
 57 |                 actor: 'bob',
 58 |                 permission: 'active',
 59 |             }],
 60 |             data: {
 61 |                 from: 'bob',
 62 |                 to: 'alice',
 63 |                 quantity: '0.0001 SYS',
 64 |                 memo: 'transactWithoutConfig2',
 65 |             },
 66 |         }]
 67 |     });
 68 | };
 69 | 
 70 | const transactWithContextFreeAction = async () => {
 71 |     return await api.transact({
 72 |         actions: [{
 73 |             account: 'cfhello',
 74 |             name: 'normal',
 75 |             authorization: [{
 76 |                 actor: 'cfactor',
 77 |                 permission: 'active'
 78 |             }],
 79 |             data: {
 80 |                 user: 'test'
 81 |             }
 82 |         }],
 83 |         context_free_actions: [{
 84 |             account: 'cfhello',
 85 |             name: 'contextfree',
 86 |             authorization: [],
 87 |             data: {}
 88 |         }]
 89 |     }, {
 90 |         blocksBehind: 3,
 91 |         expireSeconds: 30
 92 |     });
 93 | };
 94 | 
 95 | const transactWithContextFreeData = async () => {
 96 |     return await api.transact({
 97 |         actions:[{
 98 |             account: 'cfhello',
 99 |             name: 'normal',
100 |             authorization: [{
101 |                 actor: 'cfactor',
102 |                 permission: 'active'
103 |             }],
104 |             data: {
105 |                 user: 'test2'
106 |             }
107 |         }],
108 |         context_free_actions: [{
109 |             account: 'cfhello',
110 |             name: 'contextfree',
111 |             authorization: [],
112 |             data: {}
113 |         }],
114 |         context_free_data: [[ '74657374', '7465737464617461' ]]
115 |     }, {
116 |         blocksBehind: 3,
117 |         expireSeconds: 30
118 |     });
119 | };
120 | 
121 | const transactWithShorthandApiJson = async () => {
122 |     await api.getAbi('eosio.token');
123 |     return await api.transact({
124 |         actions: [
125 |             api.with('eosio.token').as('bob').transfer('bob', 'alice', '0.0001 SYS', 'transactWithShorthandApiJson')
126 |         ]
127 |     }, {
128 |         blocksBehind: 3,
129 |         expireSeconds: 30
130 |     });
131 | };
132 | 
133 | const transactWithShorthandTxJson = async () => {
134 |     await api.getAbi('eosio.token');
135 |     const tx = api.buildTransaction();
136 |     tx.with('eosio.token').as('bob').transfer('bob', 'alice', '0.0001 SYS', 'transactWithShorthandTxJson');
137 |     return await tx.send({
138 |         blocksBehind: 3,
139 |         expireSeconds: 30
140 |     });
141 | };
142 | 
143 | const transactWithShorthandTxJsonContextFreeAction = async () => {
144 |     await api.getAbi('cfhello');
145 |     const tx = api.buildTransaction();
146 |     tx.associateContextFree(() => ({
147 |         contextFreeAction: tx.with('cfhello').as().contextfree(),
148 |         action: tx.with('cfhello').as('cfactor').normal('test')
149 |     }));
150 |     return await tx.send({
151 |         blocksBehind: 3,
152 |         expireSeconds: 30
153 |     });
154 | };
155 | 
156 | const transactWithShorthandTxJsonContextFreeData = async () => {
157 |     await api.getAbi('cfhello');
158 |     const tx = api.buildTransaction();
159 |     tx.associateContextFree(() => ({
160 |         contextFreeData: [ '74657374', '7465737464617461' ],
161 |         contextFreeAction: tx.with('cfhello').as().contextfree(),
162 |         action: tx.with('cfhello').as('cfactor').normal('test2')
163 |     }));
164 |     return await tx.send({
165 |         blocksBehind: 3,
166 |         expireSeconds: 30
167 |     });
168 | };
169 | 
170 | const transactWithReturnValue = async () => {
171 |     await api.getAbi('returnvalue');
172 |     const tx = api.buildTransaction();
173 |     tx.with('returnvalue').as('bob').sum(5, 5);
174 |     return await tx.send({
175 |         blocksBehind: 3,
176 |         expireSeconds: 30
177 |     });
178 | };
179 | 
180 | const transactWithResourcePayer = async () => {
181 |     return await api.transact({
182 |         resource_payer: {
183 |             payer: 'alice',
184 |             max_net_bytes: 4096,
185 |             max_cpu_us: 400,
186 |             max_memory_bytes: 0
187 |         },
188 |         actions: [{
189 |             account: 'eosio.token',
190 |             name: 'transfer',
191 |             authorization: [{
192 |                 actor: 'bob',
193 |                 permission: 'active',
194 |             }, {
195 |                 actor: 'alice',
196 |                 permission: 'active',
197 |             }],
198 |             data: {
199 |                 from: 'bob',
200 |                 to: 'alice',
201 |                 quantity: '0.0001 SYS',
202 |                 memo: 'resource payer',
203 |             },
204 |         }]
205 |     }, {
206 |         blocksBehind: 3,
207 |         expireSeconds: 30
208 |     });
209 | };
210 | 
211 | const readOnlyQuery = async () => {
212 |     return await api.transact({
213 |         actions: [{
214 |             account: 'readonly',
215 |             name: 'get',
216 |             authorization: [{
217 |                 actor: 'readonly',
218 |                 permission: 'active',
219 |             }],
220 |             data: {},
221 |         }],
222 |     }, {
223 |         blocksBehind: 3,
224 |         expireSeconds: 30,
225 |         compression: true,
226 |         readOnlyTrx: true,
227 |     });
228 | };
229 | 
230 | const readOnlyFailureTrace = async () => {
231 |     return await api.transact({
232 |         actions: [{
233 |             account: 'eosio',
234 |             name: 'setpriv',
235 |             authorization: [{
236 |                 actor: 'bob',
237 |                 permission: 'active',
238 |             }],
239 |             data: {
240 |                 account: 'bob',
241 |                 is_priv: '1'
242 |             },
243 |         }]
244 |     }, {
245 |         blocksBehind: 3,
246 |         expireSeconds: 30,
247 |         readOnlyTrx: true,
248 |         returnFailureTraces: true,
249 |     });
250 | };
251 | 
252 | const broadcastResult = async (signaturesAndPackedTransaction) => await api.pushSignedTransaction(signaturesAndPackedTransaction);
253 | 
254 | const transactShouldFail = async () => await api.transact({
255 |     actions: [{
256 |         account: 'eosio.token',
257 |         name: 'transfer',
258 |         authorization: [{
259 |             actor: 'bob',
260 |             permission: 'active',
261 |         }],
262 |         data: {
263 |             from: 'bob',
264 |             to: 'alice',
265 |             quantity: '0.0001 SYS',
266 |             memo: '',
267 |         },
268 |     }]
269 | });
270 | 
271 | const rpcShouldFail = async () => await rpc.get_block_info(-1);
272 | 
273 | module.exports = {
274 |     transactWithConfig,
275 |     transactWithoutConfig,
276 |     transactWithContextFreeAction,
277 |     transactWithContextFreeData,
278 |     broadcastResult,
279 |     transactShouldFail,
280 |     transactWithShorthandApiJson,
281 |     transactWithShorthandTxJson,
282 |     transactWithShorthandTxJsonContextFreeAction,
283 |     transactWithShorthandTxJsonContextFreeData,
284 |     transactWithReturnValue,
285 |     transactWithResourcePayer,
286 |     readOnlyQuery,
287 |     readOnlyFailureTrace,
288 |     rpcShouldFail
289 | };
290 | 


--------------------------------------------------------------------------------
/src/tests/node.test.ts:
--------------------------------------------------------------------------------
  1 | const tests = require('./node');
  2 | 
  3 | describe('Node JS environment', () => {
  4 |     let transactionResponse: any;
  5 |     let transactionSignatures: any;
  6 |     let failedAsPlanned: boolean;
  7 | 
  8 |     it('transacts with configuration object containing blocksBehind', async () => {
  9 |         transactionResponse = await tests.transactWithConfig({
 10 |             blocksBehind: 3,
 11 |             expireSeconds: 30
 12 |         }, 'transactWithBlocksBehind');
 13 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 14 |     });
 15 | 
 16 |     it('transacts with configuration object containing useLastIrreversible', async () => {
 17 |         transactionResponse = await tests.transactWithConfig({
 18 |             useLastIrreversible: true,
 19 |             expireSeconds: 30
 20 |         }, 'transactWithUseLastIrreversible');
 21 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 22 |     });
 23 | 
 24 |     it('transacts with manually configured TAPOS fields', async () => {
 25 |         if (process.env.NODEOS_VER && process.env.NODEOS_VER === 'release/2.0.x') return;
 26 |         transactionResponse = await tests.transactWithoutConfig();
 27 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 28 |     }, 10000);
 29 | 
 30 |     it('transacts with compressed transaction', async () => {
 31 |         transactionResponse = await tests.transactWithConfig({
 32 |             blocksBehind: 3,
 33 |             expireSeconds: 30,
 34 |             compression: true
 35 |         }, 'transactWithCompression');
 36 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 37 |     });
 38 | 
 39 |     it('transacts with context free action', async () => {
 40 |         transactionResponse = await tests.transactWithContextFreeAction();
 41 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 42 |     });
 43 | 
 44 |     it('transacts with context free data', async () => {
 45 |         transactionResponse = await tests.transactWithContextFreeData();
 46 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 47 |     });
 48 | 
 49 |     it('transacts without broadcasting, returning signatures and packed transaction', async () => {
 50 |         transactionSignatures = await tests.transactWithConfig({
 51 |             broadcast: false,
 52 |             blocksBehind: 3,
 53 |             expireSeconds: 30
 54 |         }, 'transactWithoutBroadcast');
 55 |         expect(Object.keys(transactionSignatures)).toContain('signatures');
 56 |         expect(Object.keys(transactionSignatures)).toContain('serializedTransaction');
 57 |     });
 58 | 
 59 |     it('broadcasts packed transaction, given valid signatures', async () => {
 60 |         transactionSignatures = await tests.transactWithConfig({
 61 |             broadcast: false,
 62 |             blocksBehind: 3,
 63 |             expireSeconds: 30
 64 |         }, 'transactWithoutBroadcast2');
 65 |         transactionResponse = await tests.broadcastResult(transactionSignatures);
 66 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 67 |     });
 68 | 
 69 |     describe('Json Abi with Shorthand Design', () => {
 70 |         it('transacts with shorthand structure using api', async () => {
 71 |             transactionResponse = await tests.transactWithShorthandApiJson();
 72 |             expect(Object.keys(transactionResponse)).toContain('transaction_id');
 73 |         });
 74 | 
 75 |         it('transacts with shorthand structure using tx', async () => {
 76 |             transactionResponse = await tests.transactWithShorthandTxJson();
 77 |             expect(Object.keys(transactionResponse)).toContain('transaction_id');
 78 |         });
 79 | 
 80 |         it('transacts with shorthand structure using tx and context free action', async () => {
 81 |             transactionResponse = await tests.transactWithShorthandTxJsonContextFreeAction();
 82 |             expect(Object.keys(transactionResponse)).toContain('transaction_id');
 83 |         });
 84 | 
 85 |         it('transacts with shorthand structure using tx and context free data', async () => {
 86 |             transactionResponse = await tests.transactWithShorthandTxJsonContextFreeData();
 87 |             expect(Object.keys(transactionResponse)).toContain('transaction_id');
 88 |         });
 89 |     });
 90 | 
 91 |     it('transacts with elliptic p256/KeyType.R1 keys and signatures', async () => {
 92 |         transactionResponse = await tests.transactWithConfig({
 93 |             blocksBehind: 3,
 94 |             expireSeconds: 30
 95 |         }, 'transactWithR1KeySignature', 'bobr1', 'alicer1');
 96 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
 97 |     });
 98 | 
 99 |     it('confirms an action\'s return value can be verified', async () => {
100 |         if (process.env.NODEOS_VER && process.env.NODEOS_VER === 'release/2.0.x') return;
101 |         const expectedValue = 10;
102 |         transactionResponse = await tests.transactWithReturnValue();
103 |         expect(transactionResponse.processed.action_traces[0].return_value_data).toEqual(expectedValue);
104 |     });
105 | 
106 |     it('transacts with resource payer', async () => {
107 |         if (process.env.NODEOS_VER && (process.env.NODEOS_VER === 'release/2.0.x' || process.env.NODEOS_VER === 'release/2.1.x')) return;
108 |         transactionResponse = await tests.transactWithResourcePayer();
109 |         expect(Object.keys(transactionResponse)).toContain('transaction_id');
110 |     });
111 | 
112 |     it('confirms the return value of the read-only query', async () => {
113 |         if (process.env.NODEOS_VER && (process.env.NODEOS_VER === 'release/2.0.x' || process.env.NODEOS_VER === 'release/2.1.x')) return;
114 |         const expectedValue = [
115 |             {'age': 25, 'gender': 1, 'id': 1, 'name': 'Bob Smith'},
116 |             {'age': 42, 'gender': 1, 'id': 3, 'name': 'John Smith'},
117 |             {'age': 27, 'gender': 1, 'id': 4, 'name': 'Jack Smith'},
118 |             {'age': 20, 'gender': 0, 'id': 2, 'name': 'Alice Smith'},
119 |             {'age': 26, 'gender': 0, 'id': 5, 'name': 'Youko Niihara'},
120 |             {'age': 18, 'gender': 0, 'id': 6, 'name': 'Rose Lee'},
121 |             {'age': 25, 'gender': 0, 'id': 7, 'name': 'Youko Kawakami'},
122 |             {'age': 24, 'gender': 0, 'id': 8, 'name': 'Yuu Yamada'}
123 |         ];
124 |         transactionResponse = await tests.readOnlyQuery();
125 |         expect(transactionResponse.result.action_traces[0].return_value_data).toEqual(expectedValue);
126 |     });
127 | 
128 |     it('returns failure trace for failed transaction', async () => {
129 |         if (process.env.NODEOS_VER && (process.env.NODEOS_VER === 'release/2.0.x' || process.env.NODEOS_VER === 'release/2.1.x')) return;
130 |         try {
131 |             await tests.readOnlyFailureTrace();
132 |         } catch (e) {
133 |             expect(e.details.code).toEqual(3090004);
134 |             expect(e.details.stack[0].format).toEqual('missing authority of ${account}');
135 |         }
136 |     });
137 | 
138 |     it('throws appropriate error message without configuration object or TAPOS in place', async () => {
139 |         try {
140 |             failedAsPlanned = true;
141 |             await tests.transactShouldFail();
142 |             failedAsPlanned = false;
143 |         } catch (e) {
144 |             if (e.message !== 'Required configuration or TAPOS fields are not present') {
145 |                 failedAsPlanned = false;
146 |             }
147 |         }
148 |         expect(failedAsPlanned).toEqual(true);
149 |     });
150 | 
151 |     it('throws an an error with RpcError structure for invalid RPC calls', async () => {
152 |         try {
153 |             failedAsPlanned = true;
154 |             await tests.rpcShouldFail();
155 |             failedAsPlanned = false;
156 |         } catch (e) {
157 |             if (!e.json || !e.json.error || !(e.json.error.hasOwnProperty('details'))) {
158 |                 failedAsPlanned = false;
159 |             }
160 |         }
161 |         expect(failedAsPlanned).toEqual(true);
162 |     });
163 | });
164 | 


--------------------------------------------------------------------------------
/src/tests/setupJest.js:
--------------------------------------------------------------------------------
1 | global.fetch = require('jest-fetch-mock');
2 | 


--------------------------------------------------------------------------------
/src/tests/web.css:
--------------------------------------------------------------------------------
  1 | * {
  2 |   box-sizing: border-box;
  3 | }
  4 | 
  5 | html,
  6 | body {
  7 |   margin: 0;
  8 |   padding: 0;
  9 |   font-family: 'Source Sans Pro', sans-serif;
 10 | }
 11 | 
 12 | button {
 13 |   font-family: 'Source Sans Pro', sans-serif;
 14 |   font-size: .9rem;
 15 |   font-weight: 600;
 16 |   cursor: pointer;
 17 | }
 18 | 
 19 | button:active, button:focus {
 20 |   outline: none;
 21 | }
 22 | 
 23 | .header-container {
 24 |   margin: 0;
 25 |   background-color: #F6F6F8;
 26 | }
 27 | 
 28 | .header {
 29 |   display: flex;
 30 |   flex-direction: column;
 31 |   align-items: center;
 32 |   text-align: center;
 33 |   max-width: 1200px;
 34 |   margin : 0 auto;
 35 |   padding: 2rem;
 36 | }
 37 | 
 38 | .header > img { 
 39 |   max-width: 8rem;
 40 | }
 41 | 
 42 | .header > h1 {
 43 |   font-size: 3.5rem;
 44 |   font-weight: lighter;
 45 |   color: #202035;
 46 |   margin: 2rem 0;
 47 | }
 48 | 
 49 | .header > button {
 50 |   padding: 1rem 6rem;
 51 |   border-radius: .4rem;
 52 |   color: white;
 53 |   background: #15087E;
 54 |   letter-spacing: 1px;
 55 | }
 56 | 
 57 | .header > button:hover {
 58 |   background: #15089E;
 59 | }
 60 | 
 61 | .tests {
 62 |   max-width: 1200px;
 63 |   display: flex;
 64 |   flex-direction: row;
 65 |   flex-wrap: wrap;
 66 |   margin: 0 auto;
 67 |   padding: 0 1rem;
 68 | }
 69 | 
 70 | .tests > div {
 71 |   display: flex;
 72 |   flex-direction: column;
 73 |   justify-content: space-between;
 74 |   align-items: center;
 75 |   text-align: center;
 76 |   width: 30%;
 77 |   margin: 1rem auto;
 78 | }
 79 | 
 80 | .tests > div > h2 {
 81 |   font-weight: normal;
 82 |   margin: 1.5rem 0;
 83 |   font-size: .9rem;
 84 | }
 85 | 
 86 | .tests > div > button {
 87 |   width: 6.5rem;
 88 |   height: 6.5rem;
 89 |   margin: 1rem;;
 90 |   padding: 0;
 91 |   border: .15rem solid #15087E;
 92 |   border-radius: 5rem;
 93 | }
 94 | 
 95 | .tests > div > button:hover {
 96 |   background: #F6F6F8;
 97 | }
 98 | 
 99 | .tests > div > button.success {
100 |   color: #7ED321;
101 |   border: .15rem solid #7ED321;
102 | }
103 | 
104 | .tests > div > button.failed {
105 |   color: #FF6363;
106 |   border: .15rem solid #FF6363;
107 | }
108 | 
109 | @media (min-width: 1200px) {
110 |   html, body {
111 |     font-size: 20px;
112 |   }
113 | }
114 | 
115 | @media (max-width: 800px) {
116 |   html, body {
117 |     font-size: 14px;
118 |   }
119 | }
120 | 


--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "compilerOptions": {
 3 |         "target": "es5",
 4 |         "module": "CommonJS",
 5 |         "outDir": "dist",
 6 |         "alwaysStrict": true,
 7 |         "sourceMap": true,
 8 |         "noImplicitAny": true,
 9 |         "moduleResolution": "node",
10 |         "declaration": true,
11 |         "downlevelIteration": true,
12 |         "skipLibCheck": true,
13 |         "lib": [
14 |             "es2017",
15 |             "dom"
16 |         ]
17 |     },
18 |     "include": [
19 |         "src/**/*.ts",
20 |         "src/**/*.js"
21 |     ]
22 | }
23 | 


--------------------------------------------------------------------------------
/tsconfig.web.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "compilerOptions": {
 3 |         "target": "es5",
 4 |         "module": "CommonJS",
 5 |         "outDir": "dist",
 6 |         "alwaysStrict": true,
 7 |         "sourceMap": false,
 8 |         "noImplicitAny": true,
 9 |         "moduleResolution": "node",
10 |         "declaration": false,
11 |         "downlevelIteration": true,
12 |         "lib": [
13 |             "es2017",
14 |             "dom"
15 |         ]
16 |     },
17 |     "include": [
18 |         "src/**/*.ts",
19 |         "src/**/*.js"
20 |     ],
21 |     "exclude": [
22 |         "src/**/*.test.ts",
23 |         "src/tests/"
24 |     ]
25 | }
26 | 


--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "tsconfig": "tsconfig.json",
 3 |   "ignoreCompilerErrors": true,
 4 |   "hideGenerator": true,
 5 |   "includeDeclarations": false,
 6 |   "excludeExternals": true,
 7 |   "excludePrivate": true,
 8 |   "excludeProtected": true,
 9 |   "externalPattern": "**/node_modules/**",
10 |   "excludeNotExported": true,
11 |   "exclude": ["**/index*","**/*.test.ts","**/*.test.js", "**/node_modules/**"],
12 |   "mode": "modules",
13 |   "readme": "README.md",
14 |   "module": "commonjs",
15 |   "theme": "minimal",
16 |   "target": "ES5",
17 |   "out": "./reference"
18 | }
19 | 


--------------------------------------------------------------------------------
/webpack.debug.js:
--------------------------------------------------------------------------------
 1 | const path = require('path');
 2 | const webpack = require('webpack');
 3 | 
 4 | module.exports = {
 5 |     entry: {
 6 |         eosjs_api: './src/eosjs-api.ts',
 7 |         eosjs_jsonrpc: './src/rpc-web.ts',
 8 |         eosjs_jssig: './src/eosjs-jssig.ts',
 9 |         eosjs_numeric: './src/eosjs-numeric.ts',
10 |     },
11 |     devtool: 'inline-source-map',
12 |     mode: 'development',
13 |     module: {
14 |         rules: [
15 |             {
16 |                 test: /\.tsx?$/,
17 |                 use: {
18 |                     loader: 'ts-loader',
19 |                     options: {
20 |                         configFile: 'tsconfig.web.json'
21 |                     }
22 |                 },
23 |                 exclude: /node_modules/,
24 |             }
25 |         ]
26 |     },
27 |     plugins: [
28 |         new webpack.ProvidePlugin({
29 |             Buffer: ["buffer", "Buffer"],
30 |         })
31 |     ],
32 |     resolve: {
33 |         extensions: ['.tsx', '.ts', '.js'],
34 |         fallback: {
35 |             buffer: 'buffer',
36 |             crypto: 'crypto-browserify'
37 |         }
38 |     },
39 |     output: {
40 |         filename: x => x.chunk.name.replace('_', '-') + '.js',
41 |         library: '[name]',
42 |         path: path.resolve(__dirname, 'dist-web'),
43 |     },
44 |     optimization: {
45 |         splitChunks: {
46 |             cacheGroups: {
47 |                 vendor: {
48 |                     test: /[\\/]node_modules[\\/]/,
49 |                     name: 'externals',
50 |                     filename: 'externals.js',
51 |                     chunks: 'all'
52 |                 },
53 |             },
54 |         },
55 |     }
56 | };
57 | 


--------------------------------------------------------------------------------
/webpack.prod.js:
--------------------------------------------------------------------------------
 1 | const path = require('path');
 2 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
 3 | const webpack = require('webpack');
 4 | 
 5 | module.exports = {
 6 |     entry: {
 7 |         eosjs_api: './src/eosjs-api.ts',
 8 |         eosjs_jsonrpc: './src/rpc-web.ts',
 9 |         eosjs_jssig: './src/eosjs-jssig.ts',
10 |         eosjs_numeric: './src/eosjs-numeric.ts',
11 |     },
12 |     mode: 'production',
13 |     module: {
14 |         rules: [
15 |             {
16 |                 test: /\.tsx?$/,
17 |                 use: {
18 |                     loader: 'ts-loader',
19 |                     options: {
20 |                         configFile: 'tsconfig.web.json'
21 |                     }
22 |                 },
23 |                 exclude: /node_modules/,
24 |             }
25 |         ]
26 |     },
27 |     plugins: [
28 |         new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ['**/*'] }),
29 |         new webpack.ProvidePlugin({
30 |             Buffer: ["buffer", "Buffer"],
31 |         })
32 |     ],
33 |     resolve: {
34 |         extensions: ['.tsx', '.ts', '.js'],
35 |         fallback: {
36 |             buffer: 'buffer',
37 |             crypto: 'crypto-browserify'
38 |         }
39 |     },
40 |     output: {
41 |         filename: x => x.chunk.name.replace('_', '-') + '.min.js',
42 |         library: '[name]',
43 |         path: path.resolve(__dirname, 'dist-web'),
44 |     },
45 |     optimization: {
46 |         splitChunks: {
47 |             cacheGroups: {
48 |                 vendor: {
49 |                     test: /[\\/]node_modules[\\/]/,
50 |                     name: 'externals',
51 |                     filename: 'externals.min.js',
52 |                     chunks: 'all'
53 |                 },
54 |             },
55 |         },
56 |     }
57 | };
58 | 


--------------------------------------------------------------------------------