Compare commits

..
169 Commits
Author SHA1 Message Date
Github Actions 3ca07a5bc8 [CI Skip] 0.97.1
skip-checks: true
2019-11-29 09:03:39 +00:00
Jaco Greeff 89700f98c5 0.97 (#1614)
* 0.97

* Bump version, add Keys & ValidatorPrefs to CHANGELOG

* V9, V10
2019-11-29 09:55:42 +01:00
Github Actions 0cae3cf0fa [CI Skip] 0.97.0-beta.40
skip-checks: true
2019-11-28 16:31:17 +00:00
Jaco Greeff eade586044 ValidatorPrefs with commission: Perbill (#1618)
* ValidatorPrefs with commission: Perbill

* Update naming for old interfaces

* Compact commission
2019-11-28 17:24:00 +01:00
Github Actions c227c6625c [CI Skip] 0.97.0-beta.39
skip-checks: true
2019-11-28 11:50:41 +00:00
Jaco Greeff 4cb8462d50 Cleanup ABI encodeType, fix test compare (#1616) 2019-11-28 12:42:49 +01:00
Satyam Agrawal 1d671d531c update as per the 0.97.0-beta.38 release (#1617) 2019-11-28 12:41:47 +01:00
Github Actions a49cd799dd [CI Skip] 0.97.0-beta.38
skip-checks: true
2019-11-27 21:08:57 +00:00
Jaco Greeff 8ed2bda3a8 Add Polkadot AuthorityDiscovery session keys (#1573)
* Add Polkadot AuthorityDiscovery session keys

* SessionKey5 based on CC3 specVersion
2019-11-27 22:00:52 +01:00
Github Actions 2aabbe3cce [CI Skip] 0.97.0-beta.37
skip-checks: true
2019-11-27 20:38:18 +00:00
Jaco Greeff 7b37cc79a3 Add versioned chain & spec types (#1510)
* Add versioned chain & spec types

* getTypes, getVersionedTypes

* Add min/max range

* Extract specName & specVersion

* Linting

* Comment around helpers

* Split types into seperate file

* MIN, MAX comment

* version -> minmax

* Less code is always good

* Remove unused import

* Comment cleanup

* Record<string, string> -> RegistryTypes

* Cleanup linting, failing tests

* Comments
2019-11-27 21:30:57 +01:00
Github Actions 34a719e443 [CI Skip] 0.97.0-beta.36
skip-checks: true
2019-11-27 19:42:45 +00:00
Jaco Greeff b440c9b0ea Bump common (#1613) 2019-11-27 20:35:26 +01:00
Jaco Greeff 03e9a9676f Allow struct isBare with only some fields (#1611)
* Allow struct isBare with only some fields

* Add payload serialization tests
2019-11-27 20:18:10 +01:00
Github Actions 094d6f7a1c [CI Skip] 0.97.0-beta.35
skip-checks: true
2019-11-27 18:31:37 +00:00
Jaco Greeff 33fd1b1c78 Support Metadata V9 (#1600)
* Metadata v9 definitions

* Update stay V5 in V9

* WIP...

* Small adjustments

* toV9 looks sane ... may work

* v9 tests passes

* v8 tests pass... will get to overall... not checked

* Cleanup type

* Spread storage

* Missing semi

* Cleanup testUtil

* Cater for prefix map key generation

* Remove DoubleMap<T> wrapper

* Remove DoubleMap<T> wrapper

* WIP result types not yet operational

* Output formatting

* Add missing name prop

* Move v9 -> v10, v9 only as storage changes (next up)

* Support v9 & v10

* Fixup linked maps
2019-11-27 19:24:44 +01:00
Github Actions 9968aa4606 [CI Skip] 0.97.0-beta.34
skip-checks: true
2019-11-27 13:54:36 +00:00
Jaco Greeff 9c337422a5 Add derive.staking.electedInfo (#1612) 2019-11-27 14:48:00 +01:00
Github Actions cc432e2291 [CI Skip] 0.97.0-beta.33
skip-checks: true
2019-11-26 11:30:08 +00:00
Jaco Greeff aaff64404a Bump deps (#1609) 2019-11-26 12:23:12 +01:00
Github Actions bfe788cd31 [CI Skip] 0.97.0-beta.32
skip-checks: true
2019-11-26 08:11:11 +00:00
Jaco Greeff 883b191ae7 Try and detect v2 for node-template-like chains (#1607) 2019-11-26 09:04:23 +01:00
Github Actions fa46debb90 [CI Skip] 0.97.0-beta.31
skip-checks: true
2019-11-26 07:06:29 +00:00
Jaco Greeff ed4af1d04b Remove v1 era/session length changes (#1606) 2019-11-26 07:59:17 +01:00
Github Actions 4cea617b13 [CI Skip] 0.97.0-beta.30
skip-checks: true
2019-11-25 11:37:57 +00:00
Github Actions 26b6a59725 [CI Skip] 0.97.0-beta.29
skip-checks: true
2019-11-25 11:00:26 +00:00
Jaco Greeff 35c63a52c8 Add paysFee to DispatchInfo (#1604)
* Add pasyFee to DispatchInfo

* Bool -> bool
2019-11-25 11:53:22 +01:00
Github Actions 61bc20aa7b [CI Skip] 0.97.0-beta.28
skip-checks: true
2019-11-23 21:36:16 +00:00
Jaco Greeff db59fbff25 Acc contracts_getStorage (#1603) 2019-11-23 22:29:33 +01:00
Github Actions 49b3104d04 [CI Skip] 0.97.0-beta.27
skip-checks: true
2019-11-23 11:59:09 +00:00
Jaco Greeff 2338ecc2d7 Update .123trigger 2019-11-23 12:52:22 +01:00
Github Actions bab8c852a4 [CI Skip] 0.97.0-beta.26
skip-checks: true
2019-11-23 11:48:50 +00:00
Jaco Greeff cba17aeb55 Update .123trigger 2019-11-23 12:41:59 +01:00
Github Actions deca8ad216 [CI Skip] 0.97.0-beta.25
skip-checks: true
2019-11-23 11:34:26 +00:00
Jaco Greeff fb4c840549 Trigger 2019-11-23 12:27:43 +01:00
Github Actions 610234c1a1 [CI Skip] 0.97.0-beta.24
skip-checks: true
2019-11-23 11:22:27 +00:00
Jaco Greeff 7f39c573ce Add DispatchInfo (#1601)
* Add DispatchInfo

* Cleanup metadata decoration

* Assert for injection

* Appropriate metadata injection

* Fix tests
2019-11-23 12:15:36 +01:00
Github Actions 114c437671 [CI Skip] 0.97.0-beta.23
skip-checks: true
2019-11-22 20:33:37 +00:00
Jaco Greeff e12f2f67c6 trigger build 2019-11-22 21:27:03 +01:00
Github Actions 0c61850ad6 [CI Skip] 0.97.0-beta.22
skip-checks: true
2019-11-22 12:45:18 +00:00
Jaco Greeff 8b1a7a8584 Move Metadata to interfaces (#1598)
* Move Metadata to interfaces

* Align imports

* Suppress errors

* Remove TS overrides, createTypeUnsafe returns Codec

* Add type unwrap

* Fixup doc generation

* Remove V8 references
2019-11-22 13:38:20 +01:00
Github Actions 4b6b0305e6 [CI Skip] 0.97.0-beta.21
skip-checks: true
2019-11-22 09:54:10 +00:00
Jaco Greeff 3b758a0d64 Remove custom toString() from metadata storage (#1597)
* Convert asType -> asPlain, isPlainType -> isPlain

* Make tests pass

* Move unwrapStorageType to StorageKey
2019-11-22 10:47:21 +01:00
Github Actions ea2c320f33 [CI Skip] 0.97.0-beta.20
skip-checks: true
2019-11-21 20:12:56 +00:00
Jaco Greeff 306857ae07 Remove contracts v1 fees (#1596)
* Remove contracts v1 fees

* Fix linting
2019-11-21 21:06:21 +01:00
Github Actions 448ecd13bb [CI Skip] 0.97.0-beta.19
skip-checks: true
2019-11-21 15:39:22 +00:00
Jaco GreeffandAmaury Martiny 011e24bd49 Pass registry to all codec types (#1592)
* Pass registry to all codec types

* Pass through registry inside API (where the rubber meets the road)

* Small additions

* Derive w/ registry

* Types are more-or-less covered

* Some test adjustments (guided by linting)

* Rid the world of some ../injector

* Additional cleanups, merge injector into registry

* Cleanup extrinsics (always passing registry)

* Remove injector imports (not all replaced)

* Typ spec cleanups

* Phase 1 - types seem lint-free

* rpc-{core,provider} lint free

* Start working through metadata

* Small metadata additions

* Some e2e tests (out-of-order)

* Down to a handful

* Fixup tests for packages/types/src/codec/*.spec.ts

* packages/types/src/codec passes all tests

* packages/types ok (Convert storage with registry fn)

* progress (sort out injection, dreaded find-before msg)

* Down to 1 lint issue...

* Linting done... along with on-demand import

* Exposed ordering

* Remove global injects

* Cleanup comments

* Add CHANGELOG & UPGRADING

* Apply suggestions from code review

Co-Authored-By: Amaury Martiny <amaury.martiny@protonmail.com>

* Update Metadata description
2019-11-21 16:32:39 +01:00
Github Actions 099992627b [CI Skip] 0.97.0-beta.18
skip-checks: true
2019-11-20 13:05:47 +00:00
扩散性百万甜面包 74e20864a6 Typo, deocrateMethod -> decorateMethod (#1594) 2019-11-20 13:59:18 +01:00
Github Actions d006f051a3 [CI Skip] 0.97.0-beta.17
skip-checks: true
2019-11-20 12:20:36 +00:00
Mario Pino f1fe498801 Add PolkaStats to API users (#1593) 2019-11-20 13:14:03 +01:00
Github Actions 1f2cd5a6f7 [CI Skip] 0.97.0-beta.16
skip-checks: true
2019-11-19 20:48:41 +00:00
Jaco Greeff d6239cbe56 Bump metadata (#1590)
* Bump metadata

* Cleanup linting

* Build interfaces

* ... some much for "no mess, no fuss"...
2019-11-19 21:41:53 +01:00
Keith Ingram d82bb63acb Fix vec<u8> issue (#1591)
* fix vec u8 issue

* lint
2019-11-19 21:41:15 +01:00
Github Actions a3ae4cf5d2 [CI Skip] 0.97.0-beta.15
skip-checks: true
2019-11-19 15:42:05 +00:00
Jaco Greeff 6b74ea39c2 Adjust available calc (only vested, when free - reserved > vested) (#1588) 2019-11-19 16:35:28 +01:00
Github Actions 87aab2eca5 [CI Skip] 0.97.0-beta.14
skip-checks: true
2019-11-19 15:08:14 +00:00
Jaco Greeff 1c6a2582f3 Controllers on Alex (#1587) 2019-11-19 16:01:31 +01:00
Github Actions ea49095334 [CI Skip] 0.97.0-beta.13
skip-checks: true
2019-11-19 13:05:56 +00:00
Jaco Greeff b2daf7482f Types for new slashing (#1585)
* Types for new slashing

* Unwrap new nominations structures

* Small cleanups
2019-11-19 13:59:27 +01:00
Github Actions b0165e41e7 [CI Skip] 0.97.0-beta.12
skip-checks: true
2019-11-18 16:28:39 +00:00
Amaury Martiny 0a27f63423 Make api.const.*.* typed (#1584)
* Make api.const.*.* typed

* Fix tsc errors

* Remove ConstantCodec

* as any as

* Remove as any
2019-11-18 17:21:54 +01:00
Github Actions 20d8a31258 [CI Skip] 0.97.0-beta.11
skip-checks: true
2019-11-18 13:05:38 +00:00
Amaury Martiny ca186a4b2c Fix api.query.*.* typings (#1583) 2019-11-18 13:59:02 +01:00
Github Actions 7bd593c8f7 [CI Skip] 0.97.0-beta.10
skip-checks: true
2019-11-18 11:32:13 +00:00
Jaco Greeff 75220eb54f Add payment queryInfo RPC (#1580) 2019-11-18 12:26:09 +01:00
Github Actions dde7d49598 [CI Skip] 0.97.0-beta.9
skip-checks: true
2019-11-15 17:48:24 +00:00
Jaco Greeff a31921b88e Fix era countdown block indicator (#1578) 2019-11-15 18:41:51 +01:00
Github Actions a4c5ca45b2 [CI Skip] 0.97.0-beta.8
skip-checks: true
2019-11-14 17:33:44 +00:00
Jaco Greeff c44cb1858e Fix unlocking/redeemable calc with currentEra (#1572)
* Fix unlocking/redeemable calc with currentEra

* typo

* >= 0 for era check

* Reverse >= 0, it is only 0

* Pass isVesting flag via balances.all
2019-11-14 18:27:25 +01:00
Github Actions f89867a9ae [CI Skip] 0.97.0-beta.7
skip-checks: true
2019-11-14 14:37:49 +00:00
Jaco Greeff be4b9a4133 Update session keys (with AuthorityDiscovery) (#1570)
* Update session keys (with AuthorityDiscovery)

* typo
2019-11-14 15:31:22 +01:00
Github Actions 46b1429da9 [CI Skip] 0.97.0-beta.6
skip-checks: true
2019-11-14 13:58:53 +00:00
Jaco Greeff a70af20eba Derive fallbacks for election w/o electionsPhragmen (#1569) 2019-11-14 14:52:31 +01:00
Github Actions 09dc78d6b1 [CI Skip] 0.97.0-beta.5
skip-checks: true
2019-11-13 21:24:55 +00:00
Jaco Greeff 921e329d18 Cleanup decode errors (#1567)
* Cleanup decode errors

* Expand RPC error message

* Extract RPC createSignature method

* Flatten formatError

* Formatting

* Update test string match
2019-11-13 22:18:07 +01:00
Github Actions f86aebf7e1 [CI Skip] 0.97.0-beta.4
skip-checks: true
2019-11-13 10:35:10 +00:00
Jaco Greeff eef1c5327b Bump deps (#1566)
* Bump deps

* Trigger
2019-11-13 11:28:22 +01:00
Jaco Greeff 2c25936e2c Display elections runnersUp in reverse order (#1565) 2019-11-13 10:52:24 +01:00
Github Actions 734213a2f9 [CI Skip] 0.97.0-beta.3 2019-11-12 11:12:10 +00:00
Amaury Martiny 16e0ea9315 Add a Decorated class, which will be offline decorated Metadata (#1463)
* Move Metadata to api-metadata

* Make tests in api-metadata pass

* Make tests in api-metadata pass

* Refactor fromMetadata into decorated

* Fix some linting

* Replace headers

* Fix all tests

* Small lint

* Fix tests

* Fix metadata docs scripts

* Fix import ordering

* Add line breaks

* Grumbles

* Fix forgotten import

* rpcMetadata everywhere

* Fixlint

* s/api-metadata/metadata

* Fix latest tests

* Fix lint

* Fix tests
2019-11-12 12:06:18 +01:00
Github Actions c87ba33893 [CI Skip] 0.97.0-beta.2 2019-11-11 13:31:37 +00:00
Jaco Greeff 2875fdf2cf Wrap all derives in memo (like rpc-core) (#1564) 2019-11-11 14:25:07 +01:00
Github Actions e73c147275 [CI Skip] 0.97.0-beta.1 2019-11-11 10:40:15 +00:00
Jaco Greeff f080d6ed1c Bump common (#1563) 2019-11-11 11:34:08 +01:00
Github Actions 8ea07727ba [CI Skip] 0.97.0-beta.0 2019-11-10 11:31:39 +00:00
Jaco Greeff 3c47c3fdc3 Detect session.validators for derive extraction (#1562)
* Detect session.validators for derive extraction

* Add comment

* Indexed extraction without session
2019-11-10 12:25:34 +01:00
Github Actions 06418913e5 [CI Skip] 0.96.1 2019-11-09 13:30:30 +00:00
Jaco Greeff 188363d407 0.96 (#1561) 2019-11-09 14:24:27 +01:00
Github Actions ec79087bab [CI Skip] 0.96.0-beta.40 2019-11-09 11:53:53 +00:00
Jaco Greeff 155fd0f8b1 CHANGELOG for 0.96 series (#1560) 2019-11-09 12:47:06 +01:00
Github Actions 05b7def1a0 [CI Skip] 0.96.0-beta.39 2019-11-09 10:52:37 +00:00
Keith Ingram 5671af8db7 Allow most recent Result.findRecord (#1559)
* combine values

* findRecord newest

* constructor

* Add filterRecords

* Update interface
2019-11-09 11:46:09 +01:00
Github Actions 6aebeec028 [CI Skip] 0.96.0-beta.38 2019-11-08 13:53:46 +00:00
Amaury Martiny 5b5d0a3fb8 Add AuthorityList types (#1557) 2019-11-08 14:45:48 +01:00
Github Actions d405ed1005 [CI Skip] 0.96.0-beta.37 2019-11-07 20:58:26 +00:00
Jaco Greeff 2be97310d3 Add runnersup to elections (#1555) 2019-11-07 21:51:54 +01:00
Github Actions 1f44e4473f [CI Skip] 0.96.0-beta.36 2019-11-07 16:41:38 +00:00
Jaco Greeff 022c7ea645 Swap internal derives to use api.derive.* (#1553)
* Swap internal derives to use api.derive.*

* Rx vs normal decorate

* Small cleanups

* Res-use sessions

* Cleanup types

* Fix refCount lost subs

* Small cleanups
2019-11-07 17:34:53 +01:00
Github Actions fe078ca67c [CI Skip] 0.96.0-beta.35 2019-11-07 09:54:24 +00:00
Keith Ingram 479c742471 Error in ABI message assertion (#1552)
* combine values

* undefined name
2019-11-07 10:47:56 +01:00
Github Actions a52c629ecf [CI Skip] 0.96.0-beta.34 2019-11-06 22:03:58 +00:00
Jaco Greeff c077d0f2e7 Bump deps (#1550)
* Bump deps

* Updates
2019-11-06 22:56:52 +01:00
Github Actions 679994a6fb [CI Skip] 0.96.0-beta.33 2019-11-06 16:25:35 +00:00
Jaco Greeff 8cc256fdcf Derive drr doesn't have delay (#1548) 2019-11-06 17:19:12 +01:00
Github Actions b6b2f2beec [CI Skip] 0.96.0-beta.32 2019-11-05 19:04:14 +00:00
Keith Ingram 6075a21efb Handle AccountId contract params (#1547)
* combine values

* handle accountids

* cleanup

* cleanup

* force ci
2019-11-05 19:58:30 +01:00
Github Actions fa98f8f06d [CI Skip] 0.96.0-beta.31 2019-11-05 14:29:22 +00:00
Github Actions ad570cac5a [CI Skip] 0.96.0-beta.30 2019-11-05 14:20:57 +00:00
Jaco Greeff cb32acc409 Update .123trigger 2019-11-05 14:42:35 +01:00
Jaco Greeff 3998b1bcbd Whack derive memo (#1546)
* Whack derive memo

* Bump common
2019-11-05 14:36:53 +01:00
Github Actions 3fd03b2498 [CI Skip] 0.96.0-beta.29 2019-11-05 12:27:24 +00:00
Keith Ingram cba5710fec Return Codec from contracts.call (#1545)
* combine values

* Contracts with Data return

* Data toU8a()

* return data from contracts.call

* create Data

* cleanup
2019-11-05 12:56:49 +01:00
Github Actions 1ffdba03b3 [CI Skip] 0.96.0-beta.28 2019-11-05 09:33:26 +00:00
Xat_MassacrE fcf89d1501 Fix packages/types/src/codec/utils/encodeTypes.ts encodeSubTypes bug (#1544) 2019-11-05 10:27:00 +01:00
Github Actions 56dc116d92 [CI Skip] 0.96.0-beta.27 2019-11-03 22:54:20 +00:00
Jaco Greeff 2371d6a29c Remove double-up-drr (memo vs rpc) (#1541)
* Remove inner memo (no double-up on stringify)

* Validators-specific query
2019-11-03 23:47:55 +01:00
Github Actions d39878c875 [CI Skip] 0.96.0-beta.26 2019-11-03 16:21:18 +00:00
Jaco Greeff 287ceb2ded Contracts with Data return (#1540)
* Contracts with Data return

* Data toU8a()
2019-11-03 17:15:21 +01:00
Github Actions 7c04be6abc [CI Skip] 0.96.0-beta.25 2019-11-03 12:34:59 +00:00
Jaco Greeff e601ae27a1 Re-add derive memo (def. has an impact) (#1539) 2019-11-03 13:28:42 +01:00
Github Actions 487ad475c7 [CI Skip] 0.96.0-beta.24 2019-11-03 10:45:00 +00:00
Jaco Greeff 506b042f8c Remove derive memos (#1538)
* Remove derive memos

* Remove outer memo

* Over-eager replace
2019-11-03 11:38:36 +01:00
Github Actions 0e037de1b1 [CI Skip] 0.96.0-beta.23 2019-11-02 23:18:33 +00:00
Jaco Greeff 8d3cb72189 currentEraPointsEarned not on V1 2019-11-03 00:12:15 +01:00
Github Actions f8b9615e6b [CI Skip] 0.96.0-beta.22 2019-11-02 22:16:32 +00:00
Jaco Greeff 7cc961f789 Staking overview derive (#1537)
* Staking overview derive

* Expand derives

* Extract currentIndex/currentEra

* WIP

* Controllers opt

* Add memo

* Memomize the whole lot

* Doc building fixes

* Doc fixes #2
2019-11-02 23:10:10 +01:00
Github Actions 1d92b7bead [CI Skip] 0.96.0-beta.21 2019-11-01 16:22:40 +00:00
Jaco Greeff 2c44b5ca8a Add isVesting & vestingTotal to balances derive (#1536) 2019-11-01 17:16:26 +01:00
Github Actions 8d9b50a004 [CI Skip] 0.96.0-beta.20 2019-11-01 15:48:36 +00:00
Jaco Greeff d41f6ec3ef Don't re-create locks empty type, return breakdown (#1524)
* Don't re-create locks empty type

* Return the actual inv. lock information
2019-11-01 16:42:19 +01:00
Github Actions 6aff7db89a [CI Skip] 0.96.0-beta.19 2019-11-01 13:24:29 +00:00
Jaco Greeff dc105e6b31 Sub/unsub cleanups (#1535)
* Sub/unsub cleanups

* drr full idAndIndex

* Memo on nick call

* refCountDelay

* Remove scheduler param, always asap

* Flatten

* Test cleanups

* Make tests pass

* Remove logs

* Drop nick memo

* sourceConnection.unsubscribe

* Small cleanups
2019-11-01 14:17:47 +01:00
Github Actions f41ad2eee7 [CI Skip] 0.96.0-beta.18 2019-10-31 18:39:41 +00:00
Jaco Greeff 276da86dbe Expand heartbeats with num blocks (#1534) 2019-10-31 19:32:53 +01:00
Github Actions 5aa64dddf3 [CI Skip] 0.96.0-beta.17 2019-10-31 17:53:26 +00:00
Keith Ingram cf01c41b33 Contract API for Rx/promises (#1520)
* wip with rxjs/promise

* add outcome process

* contract call decoding solved

* restore messages as dict, cleanup

* linting

* linting

* type fixes
2019-10-31 19:47:14 +02:00
Github Actions 64bc3fbffa [CI Skip] 0.96.0-beta.16 2019-10-31 09:54:54 +00:00
Jaco Greeff 453aacb669 derive.accounts.info returns accountId/Index (#1533)
* derive.accounts.info returns accountId/Index

* Swap all idAndIndex to account.info
2019-10-31 10:48:29 +01:00
Github Actions 2f350e3bc2 [CI Skip] 0.96.0-beta.15 2019-10-30 13:23:24 +00:00
Jaco Greeff 8379689eaa Cleanup staking info (#1532)
* Cleanup staking info

* Cache calls

* V1, V2 (Aura & Babe) tested & working

* Hopefully pacify docs build

* Second time lucky?

* Third time lucky?

* Fouth time
2019-10-30 14:15:20 +01:00
Github Actions 2676909cd0 [CI Skip] 0.96.0-beta.14 2019-10-29 23:34:22 +00:00
Jaco Greeff a53c924248 Council -> consts (#1531)
* Council -> consts

* Additional info, expose Balance

* Types
2019-10-30 00:28:40 +01:00
Github Actions a044a959b6 [CI Skip] 0.96.0-beta.13 2019-10-29 22:32:02 +00:00
Jaco Greeff 7555a3a7ce Use currentEraStartSessionIndex for babe (#1530)
* Use currentEraStartSessionIndex for babe

* Update WithdrawReasons
2019-10-29 23:25:45 +01:00
Github Actions 0fac973645 [CI Skip] 0.96.0-beta.12 2019-10-29 21:57:20 +00:00
Jaco Greeff f533f51003 Update for latest 2.x ForceAlways (#1529) 2019-10-29 22:50:46 +01:00
Github Actions b4c0875ebf [CI Skip] 0.96.0-beta.11 2019-10-29 19:10:54 +00:00
Jaco Greeff 8cab499a83 Update .123trigger 2019-10-29 20:04:09 +01:00
Github Actions f2daae3986 [CI Skip] 0.96.0-beta.10 2019-10-29 16:56:41 +00:00
Jaco Greeff 41cf32c808 Flatten more combineLatest into queryMulti (#1528) 2019-10-29 17:49:42 +01:00
Github Actions b0e970a815 [CI Skip] 0.96.0-beta.9 2019-10-29 11:28:14 +00:00
Jaco Greeff fed9e8f7de Retrieve heartbeats for all validators (#1527)
* Retrieve heartbeats for all validators

* Tested, confirmed working
2019-10-29 12:21:49 +01:00
Github Actions d2e2d3be76 [CI Skip] 0.96.0-beta.8 2019-10-28 16:22:49 +00:00
Jaco Greeff 07b9cb1a16 Use GH_PAT is checkout action 2019-10-28 17:15:52 +01:00
Github Actions 4f24af6d8a [CI Skip] 0.96.0-beta.7 2019-10-28 13:32:14 +00:00
Jaco Greeff a30d467618 Split candidates to separate query (#1526)
* Split candidates to seperate query

* Split only candidates
2019-10-28 14:25:34 +01:00
Github Actions 3daf44bac2 [CI Skip] 0.96.0-beta.6 2019-10-28 10:20:45 +00:00
Jaco Greeff b69d8ec789 Account info derive (#1523) 2019-10-28 11:14:21 +01:00
Github Actions d1b2664071 [CI Skip] 0.96.0-beta.5 2019-10-27 12:01:45 +00:00
Jaco Greeff 8d0f20c2a7 Remove Parity Signer signature hack (#1522) 2019-10-27 12:55:01 +01:00
Github Actions f200a348de [CI Skip] 0.96.0-beta.4 2019-10-26 20:36:49 +00:00
Jaco Greeff fae67e72ee Parity Signer v4 work-around (#1521) 2019-10-26 22:30:40 +02:00
Github Actions a23e71bfb0 [CI Skip] 0.96.0-beta.3 2019-10-26 10:23:58 +00:00
Jaco Greeff 6e96fd6a55 ABI selector updates (#1517) 2019-10-26 13:17:36 +03:00
Github Actions 3ba2bbd581 [CI Skip] 0.96.0-beta.2 2019-10-26 08:38:49 +00:00
Jaco Greeff f8084c2d12 Derive for electionsPhragmen (#1519) 2019-10-26 10:32:11 +02:00
Github Actions 1ad552f03d [CI Skip] 0.96.0-beta.1 2019-10-25 15:11:30 +00:00
Jaco Greeff 6b8d0207a6 Swap to normal publish 2019-10-25 17:04:56 +02:00
477 changed files with 22777 additions and 11927 deletions
+1 -1
View File
@@ -1 +1 @@
6
13
+15 -1
View File
@@ -14,6 +14,8 @@ jobs:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
with:
token: ${{ secrets.GH_PAT }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
@@ -27,7 +29,7 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
yarn install --frozen-lockfile
CI_NO_BETA=true yarn polkadot-dev-ghact-build
yarn polkadot-dev-ghact-build
build_docs:
name: Build Docs
@@ -51,3 +53,15 @@ jobs:
run: |
yarn install --frozen-lockfile
yarn polkadot-dev-ghact-docs
dummy:
name: Dummy
if: "contains(github.event.head_commit.message, '[CI Skip]')"
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- name: dummy
run: |
echo "Dummy skip step"
+26
View File
@@ -1,3 +1,29 @@
# 0.97.1
- **Breaking change** Add the passing on an explicit `Registry` to all calls to `createType` as well as all codec classes. If you are upgrading form an older version, use the [migration guide](UPGRADING.md) to walk through the changes required.
- **Breaking change** The metadata classes have been moved from `@polkadot/types` into `@polkadot/metadata`. If you explicitly create `Metadata` classes, you now would need to do so with the `import Metadata from '@polkadot/metadata';` This is a decorated class, where the previous metadata is now available on `Metadata.metadata`, alongside decorated `consts.*`', `tx.*` and `query.*`.
- **Breaking change** Session `Keys` defaults to 4 keys now (Substrate master), depending on your node config, you would want to override with e.g. `Keys: 'SessionKeys3'` (1, 2, 3, 4, 5 & 6)
- **Breaking change** `ValidatorPrefs` now default to the new percentage commission model, to use the previous `validatorPayment`, you can override with `ValidatorPrefs: 'ValidatorPrefsTo196'`
- `api.derive.*` now has built-in memomization
- Various fixes and cleanups to `api.derive.*` including era length progress and vesting calculations
- Aligned all types with the latest Polkadot & Substrate, including Kusama CC3
- Support for Metadata V9, which adjusts the hashing methods of storage entries
- Support for Metadata V10 (still un-released), which includes prefixed map support
# 0.96.1
- Updated types for latest Kusama
- Add `filterRecords` (in addition to `findRecord`) on submittable results
- Various ABI v2 contract fixes
- Update derive for elections (incl. RunnersUp) and heartbeat derives (with blocks & messages)
- Add vesting totals & locked breakdowns to derive balances
- Update council derives for the latest Substrate master support (with constants)
- Derive cleanups, including sharing of instances between the API and internal to derives
# 0.95.2
- Temporary removal of `account_nextIndex` use, will be re-added in a future release
# 0.95.1
- Support Extrinsic V4 with additional signature indicator (Latest Polkadot/Substrate/Kusama)
+90 -6
View File
@@ -2,7 +2,91 @@
This is an upgrade guide for users of the API. It does not attempt to detail each version (the [CHANGELOG](CHANGELOG.md) has all the changes between versions), but rather tries to explain the rationale behind major breaking changes and how users of the API should handle this.
While we try to keep the user-facing interfaces as stable as possible, sometimes you just need to make additions to move forward and improve things down the road, as painful as they may be. Like you, we are also users of the API, and eat our own dogfood - and as such, feel any pains introduced first.
While we try to keep the user-facing interfaces as stable as possible, sometimes you just need to make additions to move forward and improve things down the road, as painful as they may be. Like you, we are also users of the API, and eat our own dog food - and as such, feel any pains introduced first.
## 0.97.1 (and newer), from 0.90.1 (and older)
The 0.97 series lays the groundwork to allow type registration to be ties to a specific chain and a specific Api instance. In the past, 2 Api instances in the same process would share types, which mean that you could not connect to 2 independent chains with different types. This is very problematic for Polkadot chains, where the idea is to connect to multiple chains.
When using the Api, a new `Registry` will be created on using `new Api(...)` or `Api.create(...)` and this will be transparently passed when creating types. In the cases where you create type instances explicitly or create type classes for injection, you would need to make adjustments.
### Type classes
In a number of instances, developers are creating classes and making these available for interacting with their chains. For instance, an example of a custom type could be -
```js
import { Struct, Text, u32 } from '@polkadot/types';
export class Preferences extends Struct {
constructor (value?: ahy) {
super({
name: Text,
id: u32
}, value);
}
...
}
```
In the current iteration, the underlying `@polkadot/types` bases structures now require a `Registry` to be passed as the first parameter. This means that the above signature would be adjusted to -
```js
// the next import is only required for TypeScript
import { Registry } from '@polkadot/types/types';
import { Struct, Text, u32 } from '@polkadot/types';
export class Preferences extends Struct {
constructor (registry: Registry, value?: ahy) {
super(registry, {
name: Text,
id: u32
}, value);
}
...
}
```
Where the type is used or returned from the API, the `Registry` will be automatically passed to class creation.
### createType
Previously, when creating a type instance such as `BlockNumber`, you would do `api.createType('BlockNumber', <initValue>)`, this is unchanged. In the cases where you directly import from `@polkadot/types`, the following pattern is required -
```js
import { createType } from '@polkadot/types';
...
const blockNumber = createType(api.registry, 'BlockNumber', 12345);
```
In some cases, you would want to explicitly pass a `Registry` interface to the API, instead of relying on it explicitly. This is generally applicable in the cases where you want to use the `createType` independently from the API -
```js
import { ApiPromise } from '@polkadot/api';
import { TypeRegistry, createType } from '@polkadot/types';
...
const registry = new TypeRegistry();
const blockNumber = createType(registry, 'BlockNumber', 12345);
const api = await ApiPromise.create({ registry });
```
### Extrinsic metadata
In some applications, the undocumented `findFunction` has been used to determine the Api has the metadata for a specific extrinsic. The has been exposed on top of `GenericCall`, and it typically used in applications such as signers. Along with the compulsory registry, the above functions have been moved to the `Registry` itself, so if you previously had -
```js
const { meta, method, section } = GenericCall.findFunction(extrinsic.callIndex);
```
You need to change it to -
```js
const { meta, method, section } = registry.findMetaCall(extrinsic.callIndex);
```
## 0.90.1 (and newer), from 0.81.1 (and older)
@@ -29,10 +113,10 @@ To better align with the actual types from the metadata, and avoid (too much) co
The [@polkadot/api](packages/api) has always handled the conversion of types for parameters when making calls or queries. For example, when making a transfer to `BOB` (address), any of the following is valid -
- `api.tx.balances.transfer(BOB, 12345)` - value specied as a number
- `api.tx.balances.transfer(BOB, '12345')` - value specied as a string
- `api.tx.balances.transfer(BOB, '0x3039')` - value specied as a hex
- `api.tx.balances.transfer(BOB, new BN(12345))` - value specied as a [BN](https://github.com/indutny/bn.js/)
- `api.tx.balances.transfer(BOB, 12345)` - value specified as a number
- `api.tx.balances.transfer(BOB, '12345')` - value specified as a string
- `api.tx.balances.transfer(BOB, '0x3039')` - value specified as a hex
- `api.tx.balances.transfer(BOB, new BN(12345))` - value specified as a [BN](https://github.com/indutny/bn.js/)
Internally the API will take the input and convert the value into a `Balance`, serialize it using the SCALE codec and transfer it to the node. In some cases users would construct the `Balance` type manually, by importing the class and calling `new` on it. This last approach has now been removed, and where classes are still available (limited reach), discouraged.
@@ -108,7 +192,7 @@ export class MyStruct extends Struct {
}
```
Internally the [@polkadot/types](packages/types) package now only defines classes where there are specific encoding logic applied. For all other types, the definitions are done via a JSON-like format and then the TypeScript definitions are generated from these. (In a world where nodes inject types and the type definitions are not needed, this functionality will be useful to allow TS devs to auto-generate type definitions based on what the node defines.)
Internally the [@polkadot/types](packages/types) package now only defines classes where there are specific encoding logic applied. For all other types, the definitions are done via a JSON-like format and then the TypeScript definitions are generated from these. (In a world where nodes inject types and the type definitions are not needed, this functionality will be useful to allow TS developers to auto-generate type definitions based on what the node defines.)
### Signing transactions (Signer interface)
+1 -1
View File
@@ -15,7 +15,7 @@ yarn polkadot-dev-build-ts
copy_folder "api" "api"
copy_folder "api-contract" "api-contract"
copy_folder "api-derive" "api-derive"
copy_folder "api-metadata" "api-metadata"
copy_folder "metadata" "metadata"
copy_folder "rpc-core" "rpc-core"
copy_folder "rpc-provider" "rpc-provider"
copy_folder "type-jsonrpc" "jsonrpc"
+2 -2
View File
@@ -6,8 +6,8 @@ module.exports = Object.assign({}, config, {
moduleNameMapper: {
'@polkadot/api-contract(.*)$': '<rootDir>/packages/api-contract/src/$1',
'@polkadot/api-derive(.*)$': '<rootDir>/packages/api-derive/src/$1',
'@polkadot/api-metadata(.*)$': '<rootDir>/packages/api-metadata/src/$1',
'@polkadot/api(.*)$': '<rootDir>/packages/api/src/$1',
'@polkadot/metadata(.*)$': '<rootDir>/packages/metadata/src/$1',
'@polkadot/rpc-(core|provider)(.*)$': '<rootDir>/packages/rpc-$1/src/$2',
'@polkadot/jsonrpc(.*)$': '<rootDir>/packages/type-jsonrpc/src/$1',
'@polkadot/types(.*)$': '<rootDir>/packages/types/src/$1'
@@ -16,7 +16,7 @@ module.exports = Object.assign({}, config, {
'<rootDir>/packages/api/build',
'<rootDir>/packages/api-derive/build',
'<rootDir>/packages/api-contract/build',
'<rootDir>/packages/api-metadata/build',
'<rootDir>/packages/metadata/build',
'<rootDir>/packages/rpc-core/build',
'<rootDir>/packages/rpc-provider/build',
'<rootDir>/packages/type-jsonrpc/build',
+1 -1
View File
@@ -9,5 +9,5 @@
"packages": [
"packages/*"
],
"version": "0.95.2"
"version": "0.97.1"
}
+7 -7
View File
@@ -1,5 +1,5 @@
{
"version": "0.95.2",
"version": "0.97.1",
"private": true,
"engines": {
"yarn": "^1.10.1"
@@ -9,7 +9,7 @@
],
"resolutions": {
"babel-core": "^7.0.0-bridge.0",
"typescript": "^3.6.4"
"typescript": "^3.7.2"
},
"scripts": {
"build": "yarn build:interfaces && polkadot-dev-build-ts",
@@ -28,10 +28,10 @@
"test:watch": "jest --coverage --watch"
},
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/register": "^7.6.2",
"@babel/runtime": "^7.6.3",
"@polkadot/dev": "^0.32.0-beta.11",
"@polkadot/ts": "^0.1.82"
"@babel/core": "^7.7.4",
"@babel/register": "^7.7.4",
"@babel/runtime": "^7.7.4",
"@polkadot/dev": "^0.32.0-beta.15",
"@polkadot/ts": "^0.1.86"
}
}
+4 -1
View File
@@ -3,9 +3,12 @@
Interfaces to allow for the encoding and decoding of Substrate contract ABIs.
```js
import {ApiPromise, WsProvider } from '@polkadot/api';
import { Abi } from '@polkadot/api-contract';
const abi = new Abi(<...JSON ABI...>);
const wsProvider = new WsProvider(<...Node Url...>);
const api = await ApiPromise.create({ provider: wsProvider });
const abi = new Abi(api.registry, <...JSON ABI...>);
api.tx.contracts
.call(<contract addr>, <value>, <max gas>, abi.messages.<method name>(<...params...>))
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-contract",
"version": "0.95.2",
"version": "0.97.1",
"description": "Interfaces for interacting with contracts and contract ABIs",
"main": "index.js",
"keywords": [
@@ -26,7 +26,7 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-contract#readme",
"dependencies": {
"@babel/runtime": "^7.6.3",
"@polkadot/types": "^0.95.2"
"@babel/runtime": "^7.7.4",
"@polkadot/types": "^0.97.1"
}
}
+8 -5
View File
@@ -2,21 +2,24 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import erc20Abi from '../test/contracts/Erc20.json';
import { TypeRegistry } from '@polkadot/types';
import incrementerAbi from '../test/contracts/incrementer.json';
import { Abi } from '.';
describe('Abi', (): void => {
describe('erc20', (): void => {
const registry = new TypeRegistry();
describe('incrementer', (): void => {
let abi: Abi;
beforeEach((): void => {
abi = new Abi(erc20Abi);
abi = new Abi(registry, incrementerAbi);
});
it('has the attached methods', (): void => {
expect(Object.keys(abi.messages)).toEqual(
['totalSupply', 'balanceOf', 'allowance', 'transfer', 'approve', 'transferFrom']
expect(Object.values(abi.abi.contract.messages).map(({ name }): string => name)).toEqual(
['inc', 'get', 'compare']
);
});
});
+18 -11
View File
@@ -2,7 +2,9 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABI, ContractABIPre, ContractABIFn, InterfaceAbi, AbiMessages } from './types';
import { Registry } from '@polkadot/types/types';
import { AbiConstructors, AbiMessages, ContractABI, ContractABIPre, ContractABIFn, InterfaceAbi } from './types';
import { stringCamelCase } from '@polkadot/util';
import ContractRegistry from './ContractRegistry';
@@ -10,12 +12,12 @@ import ContractRegistry from './ContractRegistry';
export default class ContractAbi extends ContractRegistry implements InterfaceAbi {
public readonly abi: ContractABI;
public readonly constructors: ContractABIFn[];
public readonly constructors: AbiConstructors;
public readonly messages: AbiMessages = {};
public readonly messages: AbiMessages;
public constructor (abi: ContractABIPre) {
super(abi);
constructor (registry: Registry, abi: ContractABIPre) {
super(registry, abi);
[this.abi, this.constructors, this.messages] = this.decodeAbi(abi);
}
@@ -25,16 +27,21 @@ export default class ContractAbi extends ContractRegistry implements InterfaceAb
const abi = this.convertAbi(abiPre);
const constructors = abi.contract.constructors.map(
(constructor, index): ContractABIFn => {
return this.createMethod(`constructor ${index}`, constructor);
return this.createMessage(`constructor ${index}`, constructor);
}
);
const messages: AbiMessages = {};
abi.contract.messages.forEach((method): void => {
const name = stringCamelCase(method.name);
const messages: AbiMessages = abi.contract.messages.reduce(
(result: AbiMessages, message): AbiMessages => {
const name = stringCamelCase(message.name);
messages[name] = this.createMethod(`messages.${name}`, method);
});
return {
...result,
[name]: this.createMessage(`messages.${name}`, message)
};
},
{}
);
return [abi, constructors, messages];
}
+75 -29
View File
@@ -2,14 +2,55 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { CodecArg, TypeDef } from '@polkadot/types/types';
import { ContractABIArgBasePre, ContractABIContract, ContractABIContractPre, ContractABIEvent, ContractABIEventPre, ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABIMethodPre, ContractABI, ContractABIPre, ContractABIRange, ContractABIRangePre, ContractABIStorage, ContractABIStorageLayout, ContractABIStorageLayoutPre, ContractABIStoragePre, ContractABIStorageStruct, ContractABIStorageStructPre, ContractABITypePre } from './types';
import { Compact } from '@polkadot/types';
import { CodecArg, Constructor, Registry, TypeDef } from '@polkadot/types/types';
import { ContractABIArgBasePre, ContractABIContract, ContractABIContractPre, ContractABIEvent, ContractABIEventPre, ContractABIFn, ContractABIFnArg, ContractABIMessage, ContractABIMessageBase, ContractABIMessagePre, ContractABI, ContractABIMessageCommon, ContractABIPre, ContractABIRange, ContractABIRangePre, ContractABIStorage, ContractABIStorageLayout, ContractABIStorageLayoutPre, ContractABIStoragePre, ContractABIStorageStruct, ContractABIStorageStructPre, ContractABITypePre } from './types';
import { assert, isNumber, isString, isNull, isObject, isUndefined, stringCamelCase } from '@polkadot/util';
import { Compact, u32, createClass, createType, encodeType } from '@polkadot/types';
import { assert, hexToU8a, isNumber, isString, isNull, isObject, isUndefined, stringCamelCase, isHex, hexToNumber } from '@polkadot/util';
import MetaRegistry from './MetaRegistry';
import { createArgClass } from './method';
// parse a selector, this can be a number (older) or of [<hex>, <hex>, ...]. However,
// just catch everything (since this is now non-standard for u32 anyway)
function parseSelector (registry: Registry, fnname: string, input: ContractABIMessageCommon['selector']): u32 {
if (isNumber(input)) {
return createType(registry, 'u32', input);
} else if (isHex(input)) {
return createType(registry, 'u32', hexToU8a(input));
} else if (typeof input === 'string') {
try {
const array = JSON.parse(input);
assert(array.length === 4, `${fnname}: Invalid selector length`);
return createType(registry, 'u32', Uint8Array.from(
// the as number[] is here to pacify TS, it doesn't quite know how to handle the cb
(array as number[]).map((value: string | number): number =>
isHex(value)
? hexToNumber(value.toString())
: value
)
));
} catch (e) {
console.error(e);
}
}
throw new Error(`${fnname}: Unable to parse selector`);
}
function createArgClass (registry: Registry, args: ContractABIFnArg[], baseDef: Record<string, string>): Constructor {
return createClass(
registry,
JSON.stringify(
args.reduce((base: Record<string, any>, { name, type }): Record<string, any> => {
base[name] = type.displayName || encodeType(type);
return base;
}, baseDef)
)
);
}
export default class ContractRegistry extends MetaRegistry {
// Contract ABI helpers
@@ -26,7 +67,7 @@ export default class ContractRegistry extends MetaRegistry {
}
public validateConstructors ({ contract: { constructors } }: ContractABIPre): void {
constructors.forEach((constructor: ContractABIMethodPre, index): void => {
constructors.forEach((constructor: ContractABIMessagePre, index): void => {
const unknownKeys = Object.keys(constructor).filter((key): boolean => !['args', 'docs', 'name', 'selector'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI constructor`);
@@ -35,45 +76,51 @@ export default class ContractRegistry extends MetaRegistry {
});
}
public validateMethods ({ contract: { messages } }: ContractABIPre): void {
messages.forEach((method): void => {
const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'docs', 'mutates', 'name', 'selector', 'return_type'].includes(key));
public validateMessages ({ contract: { messages } }: ContractABIPre): void {
messages.forEach((message): void => {
const unknownKeys = Object.keys(message).filter((key): boolean => !['args', 'docs', 'mutates', 'name', 'selector', 'return_type'].includes(key));
const fnname = `messages.${message.name}`;
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`);
const { name, selector, return_type: returnType } = method;
assert(isNumber(name) && isString(this.stringAt(name)), `Expected name for messages.${method.name}`);
assert(isNumber(selector), `Expected selector for messages.${method.name}`);
assert(isNull(returnType) || (isNumber(returnType.ty) && isObject(this.typeDefAt(returnType.ty))), `Expected return_type for messages.${method.name}`);
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${message.name}`);
this.validateArgs(`messages.${method.name}`, method.args);
const { name, selector, return_type: returnType } = message;
assert(isNumber(name) && isString(this.stringAt(name)), `Expected name for ${fnname}`);
assert(isNull(returnType) || (isNumber(returnType.ty) && isObject(this.typeDefAt(returnType.ty))), `Expected return_type for ${fnname}`);
parseSelector(this.registry, fnname, selector);
this.validateArgs(fnname, message.args);
});
}
public validateAbi (abi: ContractABIPre): void {
const unknownKeys = Object.keys(abi.contract).filter((key): boolean => !['constructors', 'docs', 'events', 'messages', 'name'].includes(key));
assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`);
const { contract: { constructors, messages, name } } = abi;
assert(constructors && messages && isString(this.stringAt(name)), 'ABI should have constructors, messages & name sections');
this.validateConstructors(abi);
this.validateMethods(abi);
this.validateMessages(abi);
}
public createMethod (name: string, method: Partial<ContractABIMethod> & ContractABIMethodBase): ContractABIFn {
const args = method.args.map(({ name, type }): ContractABIFnArg => {
public createMessage (name: string, message: Partial<ContractABIMessage> & ContractABIMessageBase): ContractABIFn {
const args = message.args.map(({ name, type }): ContractABIFnArg => {
assert(isObject(type), `Invalid type at index ${type}`);
return {
name: stringCamelCase(name),
type
};
});
const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' });
const baseStruct: { [index: string]: any } = { __selector: method.selector };
const Clazz = createArgClass(this.registry, args, isUndefined(message.selector) ? {} : { __selector: 'u32' });
const baseStruct: { [index: string]: any } = { __selector: isUndefined(message.selector) ? undefined : parseSelector(this.registry, name, message.selector) };
const encoder = (...params: CodecArg[]): Uint8Array => {
assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`);
const u8a = new Clazz(
this.registry,
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
mapped[name] = params[index];
@@ -87,9 +134,8 @@ export default class ContractRegistry extends MetaRegistry {
const fn = (encoder as ContractABIFn);
fn.args = args;
fn.isConstant = !(method.mutates || false);
fn.type = method.returnType || null;
fn.isConstant = !(message.mutates || false);
fn.type = message.returnType || null;
return fn;
}
@@ -112,7 +158,7 @@ export default class ContractRegistry extends MetaRegistry {
public convertContract ({ constructors, messages, name, events, ...contract }: ContractABIContractPre): ContractABIContract {
return {
constructors: this.convertConstructors(constructors),
messages: messages.map(method => this.convertMethod(method)),
messages: messages.map(message => this.convertMessage(message)),
name: this.stringAt(name),
...(events
? { events: events.map(event => this.convertEvent(event)) }
@@ -121,17 +167,17 @@ export default class ContractRegistry extends MetaRegistry {
};
}
public convertConstructors (constructors: ContractABIMethodPre[]): ContractABIMethod[] {
public convertConstructors (constructors: ContractABIMessagePre[]): ContractABIMessage[] {
return constructors.map(
(constructor: ContractABIMethodPre): ContractABIMethod => {
return this.convertMethod(constructor);
(constructor: ContractABIMessagePre): ContractABIMessage => {
return this.convertMessage(constructor);
}
);
}
public convertMethod ({ args, name, return_type: returnType, ...method }: ContractABIMethodPre): ContractABIMethod {
public convertMessage ({ args, name, return_type: returnType, ...message }: ContractABIMessagePre): ContractABIMessage {
return {
...method,
...message,
args: this.convertArgs(args),
name: this.stringAt(name),
returnType: returnType ? this.convertType(returnType) : null
+22 -13
View File
@@ -2,32 +2,41 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import fs from 'fs';
import path from 'path';
import { TypeRegistry } from '@polkadot/types';
import MetaRegistry from './MetaRegistry';
import erc20Abi from '../test/contracts/Erc20.json';
import erc20Cmp from '../test/compare/erc20.test.json';
import sharedVecAbi from '../test/contracts/SharedVecV2.json';
import sharedVecCmp from '../test/compare/shared-vec.test.json';
import test001Abi from '../test/abi/test001.json';
import test001Cmp from '../test/compare/test001.cmp.json';
function compare (meta: MetaRegistry, other: any): void {
try {
expect(meta.typeDefs).toEqual(other);
} catch (error) {
console.error(JSON.stringify(meta.typeDefs));
throw error;
}
}
describe('MetaRegistry', (): void => {
const registry = new TypeRegistry();
describe('construction', (): void => {
it('initializes from a contract ABI (ERC20)', (): void => {
const metaRegistry = new MetaRegistry(erc20Abi);
fs.writeFile(path.join(__dirname, '../test/compare/erc20.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
if (err) throw err;
});
expect(true).toBe(true);
compare(new MetaRegistry(registry, erc20Abi), erc20Cmp);
});
it('initializes from a contract ABI (SharedVec)', (): void => {
const metaRegistry = new MetaRegistry(sharedVecAbi);
fs.writeFile(path.join(__dirname, '../test/compare/shared-vec.test.json'), JSON.stringify(metaRegistry.typeDefs, null, 2), function (err): void {
if (err) throw err;
});
compare(new MetaRegistry(registry, sharedVecAbi), sharedVecCmp);
});
expect(true).toBe(true);
it('initializes from a contract ABI (Other, test001)', (): void => {
compare(new MetaRegistry(registry, test001Abi), test001Cmp);
});
});
});
+7 -4
View File
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { MetaRegistryItem, MetaRegistryJson, MetaTypeDefClikeEnum, MetaType, MetaTypeDefEnum, MetaTypeDefEnumVariant, MetaTypeDefEnumVariantStruct, MetaTypeDefEnumVariantTupleStruct, MetaTypeDefEnumVariantUnit, MetaTypeDefStruct, MetaTypeDefStructField, MetaTypeDefTupleStruct, MetaTypeDefUnion, MetaTypeIdCustom, MetaTypeIdVec, MetaTypeIdVecFixed, MetaTypeInfo, StringIndex, TypeDef, TypeDefInfo, TypeIndex } from '@polkadot/types/types';
import { MetaRegistryItem, MetaRegistryJson, MetaTypeDefClikeEnum, MetaType, MetaTypeDefEnum, MetaTypeDefEnumVariant, MetaTypeDefEnumVariantStruct, MetaTypeDefEnumVariantTupleStruct, MetaTypeDefEnumVariantUnit, MetaTypeDefStruct, MetaTypeDefStructField, MetaTypeDefTupleStruct, MetaTypeDefUnion, MetaTypeIdCustom, MetaTypeIdVec, MetaTypeIdVecFixed, MetaTypeInfo, Registry, StringIndex, TypeDef, TypeDefInfo, TypeIndex } from '@polkadot/types/types';
import { assert } from '@polkadot/util';
import { displayType, withTypeString } from '@polkadot/types';
@@ -34,13 +34,16 @@ function detectedType ({ def, id }: MetaType): MetaTypeInfo {
}
class MetadataRegistryLookup {
public readonly registry: Registry;
protected _strings: string[] = [];
protected _types: MetaType[] = [];
public typeDefs: TypeDef[] = [];
public constructor ({ registry: { strings, types } }: MetaRegistryJson) {
constructor (registry: Registry, { registry: { strings, types } }: MetaRegistryJson) {
this.registry = registry;
this._strings = strings;
this._types = types;
}
@@ -102,8 +105,8 @@ class MetadataRegistryLookup {
}
export default class MetaRegistry extends MetadataRegistryLookup {
public constructor (json: MetaRegistryJson) {
super(json);
constructor (registry: Registry, json: MetaRegistryJson) {
super(registry, json);
// Generate TypeDefs for each provided registry type
this._types.forEach((_, index: number): void => this.setTypeDefAtIndex(index + 1));
-31
View File
@@ -1,31 +0,0 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableModuleExtrinsics } from '@polkadot/api/types';
import { ApiObject, ContractABIPre, ContractBase } from './types';
import { assert } from '@polkadot/util';
import Abi from './Abi';
// NOTE Experimental, POC, bound to change
export default abstract class RxBase implements ContractBase<'rxjs'> {
public readonly abi: Abi;
public readonly api: ApiObject<'rxjs'>;
public readonly apiContracts: SubmittableModuleExtrinsics<'rxjs'>;
public constructor (api: ApiObject<'rxjs'>, abi: ContractABIPre | Abi) {
this.abi = abi instanceof Abi
? abi
: new Abi(abi);
this.api = api;
// cater for substrate 2.x & 1.x (in order)
this.apiContracts = api.tx.contracts || api.tx.contract;
assert(this.apiContracts && this.apiContracts.putCode, 'You need to connect to a node with the contracts module, the metadata does not enable api.tx.contracts on this instance');
}
}
-72
View File
@@ -1,72 +0,0 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableResultImpl } from '@polkadot/api/types';
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ContractABIPre } from './types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiRx, SubmittableResult } from '@polkadot/api';
import { createType } from '@polkadot/types';
import { assert } from '@polkadot/util';
import Abi from './Abi';
import RxBase from './RxBase';
import RxContract from './RxContract';
type BlueprintCreateResultSubscription = Observable<BlueprintCreateResult>;
export interface BlueprintCreate {
signAndSend (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription;
}
class BlueprintCreateResult extends SubmittableResult {
public readonly contract?: RxContract;
public constructor (result: SubmittableResultImpl, contract?: RxContract) {
super(result);
this.contract = contract;
}
}
// NOTE Experimental, POC, bound to change
export default class Blueprint extends RxBase {
public readonly codeHash: Hash;
public constructor (api: ApiRx, abi: ContractABIPre | Abi, codeHash: string | Hash) {
super(api, abi);
this.codeHash = createType('Hash', codeHash);
}
public deployContract (constructorIndex = 0, endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate {
assert(!!this.abi.constructors[constructorIndex], `Specified constructor index ${constructorIndex} does not exist`);
const signAndSend = (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription => {
return this.apiContracts
.create(endowment, maxGas, this.codeHash, this.abi.constructors[constructorIndex](...params))
.signAndSend(account)
.pipe(map(this.createResult));
};
return { signAndSend };
}
private createResult = (result: SubmittableResult): BlueprintCreateResult => {
let contract: RxContract | undefined;
if (result.isFinalized) {
const record = result.findRecord('contract', 'Instantiated');
if (record) {
contract = new RxContract(this.api, this.abi, record.event.data[1] as Address);
}
}
return new BlueprintCreateResult(result, contract);
}
}
-83
View File
@@ -1,83 +0,0 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableResultImpl } from '@polkadot/api/types';
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ContractABIPre } from './types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiRx, SubmittableResult } from '@polkadot/api';
import { compactAddLength, u8aToU8a } from '@polkadot/util';
import Abi from './Abi';
import RxBase from './RxBase';
import RxBlueprint from './RxBlueprint';
// Ok, tried, failed, eventually ... well, we are only trying with RxJs as a
// start, so take a big fat shortcut with this version, real intended version
// follows this and is commented out
type CodePutCodeResultSubscription = Observable<CodePutCodeResult>;
// type ICodePutCodeResultSubscription<ApiType> =
// ApiType extends 'rxjs'
// ? Observable<CodePutCodeResult>
// : Promise<() => void>;
// unlike the ISubmittableExtrinsic, it doesn't extend IExtrinsic and only
// implements one var iant of signAndSend - this is purely done to see what
// is hanging where, with the bare-mainimum from a simplicity perspective
// Very obvious is that it supports only 1 version of signAndSend
// (we need to revisit this, but probably ok for initial?)
// eslint-disable-next-line @typescript-eslint/interface-name-prefix
export interface CodePutCode {
signAndSend (account: IKeyringPair | string | AccountId | Address): CodePutCodeResultSubscription;
}
class CodePutCodeResult extends SubmittableResult {
public readonly blueprint?: RxBlueprint;
public constructor (result: SubmittableResultImpl, blueprint?: RxBlueprint) {
super(result);
this.blueprint = blueprint;
}
}
// NOTE Experimental, POC, bound to change
export default class RxCode extends RxBase {
public readonly code: Uint8Array;
public constructor (api: ApiRx, abi: ContractABIPre | Abi, wasm: string | Uint8Array) {
super(api, abi);
this.code = u8aToU8a(wasm);
}
public createBlueprint (maxGas: number | BN): CodePutCode {
const signAndSend = (account: IKeyringPair | string | AccountId | Address): CodePutCodeResultSubscription => {
return this.apiContracts
.putCode(maxGas, compactAddLength(this.code))
.signAndSend(account)
.pipe(map(this.createResult));
};
return { signAndSend };
}
private createResult = (result: SubmittableResultImpl): CodePutCodeResult => {
let blueprint: RxBlueprint | undefined;
if (result.isFinalized) {
const record = result.findRecord('contract', 'CodeStored');
if (record) {
blueprint = new RxBlueprint(this.api, this.abi, record.event.data[0] as Hash);
}
}
return new CodePutCodeResult(result, blueprint);
}
}
-41
View File
@@ -1,41 +0,0 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Address } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ContractABIPre, ContractABIFn, InterfaceContract, InterfaceContractCalls } from './types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { ApiRx, SubmittableResult } from '@polkadot/api';
import { createType } from '@polkadot/types';
import Abi from './Abi';
import RxBase from './RxBase';
export type ContractCallResultSubscription = Observable<SubmittableResult>;
export interface ContractCall {
signAndSend (account: IKeyringPair | string | AccountId | Address): ContractCallResultSubscription;
}
type CallResult = (value: BN | number, maxGas: BN | number, ...params: any[]) => ContractCall;
// NOTE Experimental, POC, bound to change
export default class RxContract extends RxBase implements InterfaceContract {
public readonly address: Address;
public readonly calls: InterfaceContractCalls = {};
public constructor (api: ApiRx, abi: ContractABIPre | Abi, address: string | AccountId | Address) {
super(api, abi);
this.address = createType('Address', address);
Object.entries(this.abi.messages).forEach(([name]): void => {
this.calls[name] = (fn: ContractABIFn): CallResult =>
(value: BN | number, maxGas: BN | number, ...params: any[]): ContractCall =>
this.apiContracts.call(this.address, value, maxGas, fn(...params));
});
}
}
@@ -0,0 +1,75 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiTypes, DecorateMethod, SubmittableResultImpl } from '@polkadot/api/types';
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ApiObject, ContractABIPre } from '../types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { SubmittableResult } from '@polkadot/api';
import { createType } from '@polkadot/types';
import { assert } from '@polkadot/util';
import Abi from '../Abi';
import Contract from './Contract';
import { BaseWithTx } from './util';
type BlueprintCreateResultSubscription<ApiType extends ApiTypes> = Observable<BlueprintCreateResult<ApiType>>;
export interface BlueprintCreate<ApiType extends ApiTypes> {
signAndSend (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription<ApiType>;
}
class BlueprintCreateResult<ApiType extends ApiTypes> extends SubmittableResult {
public readonly contract?: Contract<ApiType>;
constructor (result: SubmittableResultImpl, contract?: Contract<ApiType>) {
super(result);
this.contract = contract;
}
}
// NOTE Experimental, POC, bound to change
export default class Blueprint<ApiType extends ApiTypes> extends BaseWithTx<ApiType> {
public readonly codeHash: Hash;
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>, codeHash: string | Hash) {
super(api, abi, decorateMethod);
this.codeHash = createType(this.registry, 'Hash', codeHash);
}
public deployContract (constructorIndex = 0, endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate<ApiType> {
assert(!!this.abi.constructors[constructorIndex], `Specified constructor index ${constructorIndex} does not exist`);
return {
signAndSend: this.decorateMethod(
(account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription<ApiType> => {
return this.apiContracts
.create(endowment, maxGas, this.codeHash, this.abi.constructors[constructorIndex](...params))
.signAndSend(account)
.pipe(map(this.createResult));
}
)
};
}
private createResult = (result: SubmittableResult): BlueprintCreateResult<ApiType> => {
let contract: Contract<ApiType> | undefined;
if (result.isFinalized) {
const record = result.findRecord('contract', 'Instantiated');
if (record) {
contract = new Contract<ApiType>(this.api, this.abi, this.decorateMethod, record.event.data[1] as Address);
}
}
return new BlueprintCreateResult(result, contract);
}
}
+71
View File
@@ -0,0 +1,71 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiTypes, DecorateMethod, SubmittableResultImpl } from '@polkadot/api/types';
import { AccountId, Address, Hash } from '@polkadot/types/interfaces';
import { IKeyringPair } from '@polkadot/types/types';
import { ApiObject, ContractABIPre } from '../types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { SubmittableResult } from '@polkadot/api';
import { compactAddLength, u8aToU8a } from '@polkadot/util';
import Abi from '../Abi';
import Blueprint from './Blueprint';
import { BaseWithTx } from './util';
type CodePutCodeResultSubscription<ApiType extends ApiTypes> = Observable<CodePutCodeResult<ApiType>>;
// eslint-disable-next-line @typescript-eslint/interface-name-prefix
export interface CodePutCode<ApiType extends ApiTypes> {
signAndSend (account: IKeyringPair | string | AccountId | Address): CodePutCodeResultSubscription<ApiType>;
}
class CodePutCodeResult<ApiType extends ApiTypes> extends SubmittableResult {
public readonly blueprint?: Blueprint<ApiType>;
constructor (result: SubmittableResultImpl, blueprint?: Blueprint<ApiType>) {
super(result);
this.blueprint = blueprint;
}
}
// NOTE Experimental, POC, bound to change
export default class Code<ApiType extends ApiTypes> extends BaseWithTx<ApiType> {
public readonly code: Uint8Array;
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>, wasm: string | Uint8Array) {
super(api, abi, decorateMethod);
this.code = u8aToU8a(wasm);
}
public createBlueprint = (maxGas: number | BN): CodePutCode<ApiType> => {
return {
signAndSend: this.decorateMethod(
(account: IKeyringPair | string | AccountId | Address): CodePutCodeResultSubscription<ApiType> => this.apiContracts
.putCode(maxGas, compactAddLength(this.code))
.signAndSend(account)
.pipe(map(this.createResult))
)
};
}
private createResult = (result: SubmittableResultImpl): CodePutCodeResult<ApiType> => {
let blueprint: Blueprint<ApiType> | undefined;
if (result.isFinalized) {
const record = result.findRecord('contract', 'CodeStored');
if (record) {
blueprint = new Blueprint<ApiType>(this.api, this.abi, this.decorateMethod, record.event.data[0] as Hash);
}
}
return new CodePutCodeResult(result, blueprint);
}
}
@@ -0,0 +1,97 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiTypes, DecorateMethod, ObsInnerType } from '@polkadot/api/types';
import { AccountId, Address, ContractExecResult } from '@polkadot/types/interfaces';
import { Codec, IKeyringPair } from '@polkadot/types/types';
import { ApiObject, ContractABIMessage, ContractABIPre, ContractCallOutcome } from '../types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { SubmittableResult } from '@polkadot/api';
import { createType } from '@polkadot/types';
import Abi from '../Abi';
import { formatData } from '../util';
import { BaseWithTxAndRpcCall } from './util';
type ContractCallTypes = 'tx' | 'rpc';
type ContractCallResultSubscription<ApiType extends ApiTypes, CallType extends ContractCallTypes> = ApiType extends 'rxjs'
? Observable<ContractCallResult<CallType>>
: Promise<ObsInnerType<ContractCallResult<CallType>>>;
// eslint-disable-next-line @typescript-eslint/interface-name-prefix
export interface ContractCall<ApiType extends ApiTypes, CallType extends ContractCallTypes> {
send (account: IKeyringPair | string | AccountId | Address): ContractCallResultSubscription<ApiType, CallType>;
}
export type ContractCallResult<CallType extends ContractCallTypes> = CallType extends 'rpc'
? Observable<ContractCallOutcome>
: Observable<SubmittableResult>;
export default class Contract<ApiType extends ApiTypes> extends BaseWithTxAndRpcCall<ApiType> {
public readonly address: Address;
public call (as: 'rpc', message: string, value: BN | number, gasLimit: BN | number, ...params: any[]): ContractCall<ApiType, 'rpc'>;
public call (as: 'tx', message: string, value: BN | number, gasLimit: BN | number, ...params: any[]): ContractCall<ApiType, 'tx'>;
public call<CallType extends ContractCallTypes> (as: CallType, message: string, value: BN | number, gasLimit: BN | number, ...params: any[]): ContractCall<ApiType, CallType> {
const { fn, def } = this.getMessage(message);
return {
send: this.decorateMethod(
as === 'rpc'
? (account: IKeyringPair | string | AccountId | Address): ContractCallResult<'rpc'> => {
return this.rpcContractsCall(
createType(this.registry, 'ContractCallRequest', {
origin: account,
dest: this.address.toString(),
value,
gasLimit,
inputData: fn(...params)
})
)
.pipe(
map((result: ContractExecResult): ContractCallOutcome =>
this.createOutcome(result, createType(this.registry, 'AccountId', account), def, params)
)
);
}
: (account: IKeyringPair | string | AccountId | Address): ContractCallResult<'tx'> => {
return this.apiContracts
.call(this.address, value, gasLimit, fn(...params))
.signAndSend(account);
}
)
};
}
private createOutcome (result: ContractExecResult, origin: AccountId, message: ContractABIMessage, params: any[]): ContractCallOutcome {
let output: Codec | null = null;
if (result.isSuccess) {
const { data } = result.asSuccess;
output = message.returnType
? formatData(this.registry, data, message.returnType)
: createType(this.registry, 'Data', data);
}
return {
time: Date.now(),
message,
origin,
params,
result,
isSuccess: result.isSuccess,
output
};
}
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>, address: string | AccountId | Address) {
super(api, abi, decorateMethod);
this.address = createType(this.registry, 'Address', address);
}
}
+7
View File
@@ -0,0 +1,7 @@
// Copyright 2017-2019 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export { default as Blueprint } from './Blueprint';
export { default as Code } from './Code';
export { default as Contract } from './Contract';
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2017-2019 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiTypes, DecorateMethod, DecoratedRpc, SubmittableModuleExtrinsics } from '@polkadot/api/types';
import { ApiObject, ContractABIMessage, ContractABIPre, ContractBase, ContractMessage } from '../types';
import { RpcInterface } from '@polkadot/rpc-core/jsonrpc.types';
import { Registry } from '@polkadot/types/types';
import { assert, stringCamelCase } from '@polkadot/util';
import Abi from '../Abi';
export abstract class Base<ApiType extends ApiTypes> implements ContractBase<ApiType> {
public readonly abi: Abi;
public readonly api: ApiObject<ApiType>;
public readonly decorateMethod: DecorateMethod<ApiType>;
public readonly registry: Registry;
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>) {
this.abi = abi instanceof Abi
? abi
: new Abi(api.registry, abi);
this.registry = api.registry;
this.api = api;
this.decorateMethod = decorateMethod;
}
public get messages (): ContractMessage[] {
return this.abi.abi.contract.messages
.map(
(def: ContractABIMessage, index): ContractMessage => ({
index,
def,
fn: this.abi.messages[def.name] || this.abi.messages[stringCamelCase(name)]
})
);
}
public getMessage (nameOrIndex?: string | number): ContractMessage {
const index = nameOrIndex
? typeof nameOrIndex === 'number'
? nameOrIndex
: this.abi.abi.contract.messages.findIndex((message): boolean => nameOrIndex === message.name || nameOrIndex === stringCamelCase(message.name))
: 0;
const def = this.abi.abi.contract.messages[index];
assert(!!def, `Attempted to access a contract message that does not exist: ${typeof nameOrIndex === 'number' ? `index ${nameOrIndex}` : nameOrIndex}`);
const fn = this.abi.messages[def.name] || this.abi.messages[stringCamelCase(def.name)];
return { index, def, fn };
}
}
export abstract class BaseWithTx<ApiType extends ApiTypes> extends Base<ApiType> {
protected get apiContracts (): SubmittableModuleExtrinsics<'rxjs'> {
return this.api.rx.tx.contracts;
}
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>) {
super(api, abi, decorateMethod);
assert(this.api.rx.tx.contracts && this.api.rx.tx.contracts.putCode, 'You need to connect to a node with the contracts module, the metadata does not enable api.tx.contracts on this instance');
}
}
export abstract class BaseWithTxAndRpcCall<ApiType extends ApiTypes> extends BaseWithTx<ApiType> {
protected get rpcContractsCall (): DecoratedRpc<'rxjs', RpcInterface>['contracts']['call'] {
return this.api.rx.rpc.contracts.call;
}
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>) {
super(api, abi, decorateMethod);
assert(this.api.rx.rpc.contracts && this.api.rx.tx.contracts.call, 'You need to connect to a node with the contracts module, the metadata does not enable api.rpc.contracts.call on this instance');
}
}
+2 -3
View File
@@ -3,6 +3,5 @@
// of the Apache-2.0 license. See the LICENSE file for details.
export { default as Abi } from './Abi';
export { default as RxBlueprint } from './RxBlueprint';
export { default as RxCode } from './RxCode';
export { default as RxContract } from './RxContract';
export * from './rx';
export * from './promise';
-20
View File
@@ -1,20 +0,0 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Constructor } from '@polkadot/types/types';
import { ContractABIFnArg } from './types';
import { createClass, encodeType } from '@polkadot/types';
export function createArgClass (args: ContractABIFnArg[], baseDef: Record<string, string>): Constructor {
return createClass(
JSON.stringify(
args.reduce((base: Record<string, any>, { name, type }): Record<string, any> => {
base[name] = encodeType(type);
return base;
}, baseDef)
)
);
}
@@ -0,0 +1,18 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Hash } from '@polkadot/types/interfaces';
import { ContractABIPre } from '../types';
import { ApiPromise } from '@polkadot/api';
import { decorateMethod } from '@polkadot/api/promise';
import Abi from '../Abi';
import Blueprint from '../base/Blueprint';
export default class PromiseBlueprint extends Blueprint<'promise'> {
constructor (api: ApiPromise, abi: ContractABIPre | Abi, codeHash: string | Hash) {
super(api, abi, decorateMethod, codeHash);
}
}
@@ -0,0 +1,17 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABIPre } from '../types';
import { ApiPromise } from '@polkadot/api';
import { decorateMethod } from '@polkadot/api/promise';
import Abi from '../Abi';
import Code from '../base/Code';
export default class PromiseCode extends Code<'promise'> {
constructor (api: ApiPromise, abi: ContractABIPre | Abi, wasm: string | Uint8Array) {
super(api, abi, decorateMethod, wasm);
}
}
@@ -0,0 +1,18 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types/interfaces';
import { ContractABIPre } from '../types';
import { ApiPromise } from '@polkadot/api';
import { decorateMethod } from '@polkadot/api/promise';
import Abi from '../Abi';
import Contract from '../base/Contract';
export default class PromiseContract extends Contract<'promise'> {
constructor (api: ApiPromise, abi: ContractABIPre | Abi, address: string | AccountId) {
super(api, abi, decorateMethod, address);
}
}
@@ -0,0 +1,7 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export { default as PromiseBlueprint } from './PromiseBlueprint';
export { default as PromiseCode } from './PromiseCode';
export { default as PromiseContract } from './PromiseContract';
@@ -0,0 +1,18 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Hash } from '@polkadot/types/interfaces';
import { ContractABIPre } from '../types';
import { ApiRx } from '@polkadot/api';
import { decorateMethod } from '@polkadot/api/rx';
import Abi from '../Abi';
import Blueprint from '../base/Blueprint';
export default class RxBlueprint extends Blueprint<'rxjs'> {
constructor (api: ApiRx, abi: ContractABIPre | Abi, codeHash: string | Hash) {
super(api, abi, decorateMethod, codeHash);
}
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABIPre } from '../types';
import { ApiRx } from '@polkadot/api';
import { decorateMethod } from '@polkadot/api/rx';
import Abi from '../Abi';
import Code from '../base/Code';
export default class RxCode extends Code<'rxjs'> {
constructor (api: ApiRx, abi: ContractABIPre | Abi, wasm: string | Uint8Array) {
super(api, abi, decorateMethod, wasm);
}
}
@@ -0,0 +1,18 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types/interfaces';
import { ContractABIPre } from '../types';
import { ApiRx } from '@polkadot/api';
import { decorateMethod } from '@polkadot/api/rx';
import Abi from '../Abi';
import Contract from '../base/Contract';
export default class RxContract extends Contract<'rxjs'> {
constructor (api: ApiRx, abi: ContractABIPre | Abi, address: string | AccountId) {
super(api, abi, decorateMethod, address);
}
}
+7
View File
@@ -0,0 +1,7 @@
// Copyright 2017-2019 @polkadot/api-contract authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
export { default as RxBlueprint } from './RxBlueprint';
export { default as RxCode } from './RxCode';
export { default as RxContract } from './RxContract';
+49 -27
View File
@@ -2,17 +2,26 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubmittableModuleExtrinsics } from '@polkadot/api/types';
import { Address } from '@polkadot/types/interfaces';
import { CodecArg } from '@polkadot/types/types';
import { ApiTypes, DecorateMethod } from '@polkadot/api/types';
import { AccountId, Address, ContractExecResult } from '@polkadot/types/interfaces';
import { Codec, CodecArg } from '@polkadot/types/types';
import { MetaRegistryJson, StringIndex, TypeIndex, TypeDef } from '@polkadot/types/codec/create/types';
// import { Observable } from 'rxjs';
import { ApiPromise, ApiRx } from '@polkadot/api';
export type ApiObject<ApiType> = ApiType extends 'rxjs'
export type ApiObject<ApiType extends ApiTypes> = ApiType extends 'rxjs'
? ApiRx
: ApiPromise;
export interface ContractBase<ApiType extends ApiTypes> {
readonly abi: InterfaceAbi;
readonly api: ApiObject<ApiType>;
readonly decorateMethod: DecorateMethod<ApiType>;
getMessage: (name: string) => ContractMessage;
messages: ContractMessage[];
}
export interface ContractABITypePre {
ty: TypeIndex;
display_name: StringIndex[];
@@ -28,31 +37,31 @@ export interface ContractABIArgBase {
type: TypeDef;
}
export type ContractABIMethodArgPre = ContractABIArgBasePre;
export type ContractABIMessageArgPre = ContractABIArgBasePre;
export type ContractABIMethodArg = ContractABIArgBase;
export type ContractABIMessageArg = ContractABIArgBase;
export interface ContractABIMethodBase {
args: ContractABIMethodArg[];
export interface ContractABIMessageBase {
args: ContractABIMessageArg[];
}
export interface ContractABIMethodBasePre {
args: ContractABIMethodArgPre[];
export interface ContractABIMessageBasePre {
args: ContractABIMessageArgPre[];
}
export interface ContractABIMethodCommon {
export interface ContractABIMessageCommon {
docs?: ContractABIDocs;
mutates?: boolean;
selector: number;
selector: string | number;
}
export interface ContractABIMethodPre extends ContractABIMethodCommon, ContractABIMethodBasePre {
export interface ContractABIMessagePre extends ContractABIMessageCommon, ContractABIMessageBasePre {
name: StringIndex;
return_type: ContractABITypePre | null;
}
export interface ContractABIMethod extends ContractABIMethodCommon {
args: ContractABIMethodArg[];
export interface ContractABIMessage extends ContractABIMessageCommon {
args: ContractABIMessageArg[];
name: string;
returnType: TypeDef | null;
}
@@ -62,16 +71,16 @@ export interface ContractABIContractCommon {
}
export interface ContractABIContractPre extends ContractABIContractCommon {
constructors: ContractABIMethodPre[];
messages: ContractABIMethodPre[];
constructors: ContractABIMessagePre[];
messages: ContractABIMessagePre[];
name: StringIndex;
events?: ContractABIEventPre[];
docs?: ContractABIDocs;
}
export interface ContractABIContract extends ContractABIContractCommon {
constructors: ContractABIMethod[];
messages: ContractABIMethod[];
constructors: ContractABIMessage[];
messages: ContractABIMessage[];
name: string;
events?: ContractABIEvent[];
docs?: ContractABIDocs;
@@ -121,7 +130,8 @@ export interface ContractABIEvent {
}
export interface ContractABIRangeBase {
'range.offset': number[];
// can be number[] (old) or hex (new)
'range.offset': number[] | string;
'range.len': number;
}
@@ -161,20 +171,22 @@ export type ContractABIStoragePre = ContractABIStorageStructPre;
export type ContractABIStorage = ContractABIStorageStruct;
export interface ContractMessage {
index: number;
fn: ContractABIFn;
def: ContractABIMessage;
}
export type AbiConstructors = ContractABIFn[];
export type AbiMessages = Record<string, ContractABIFn>;
export interface InterfaceAbi {
readonly abi: ContractABI;
readonly constructors: ContractABIFn[];
readonly constructors: AbiConstructors;
readonly messages: AbiMessages;
}
export interface ContractBase<ApiType> {
readonly abi: InterfaceAbi;
readonly api: ApiObject<ApiType>;
readonly apiContracts: SubmittableModuleExtrinsics<ApiType>;
}
export interface InterfaceContractCalls {
[index: string]: Function;
}
@@ -183,3 +195,13 @@ export interface InterfaceContract {
readonly address: Address;
readonly calls: InterfaceContractCalls;
}
export interface ContractCallOutcome {
time: number;
result: ContractExecResult;
origin: AccountId;
output: Codec | null;
params: any[];
isSuccess: boolean;
message: ContractABIMessage;
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2019 @polkadot/rpc-core authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Codec, Registry, TypeDefInfo, TypeDef } from '@polkadot/types/types';
import { Data, Option, createClass } from '@polkadot/types';
import { createTypeUnsafe } from '@polkadot/types/codec';
export function formatData (registry: Registry, data: Data, { info, type }: TypeDef): Codec {
const u8a = data.toU8a();
if (info === TypeDefInfo.Option) {
return new Option(
registry,
createClass(registry, type),
createTypeUnsafe(registry, type, [u8a], true)
);
}
return createTypeUnsafe(registry, type, [u8a], true);
}
+467
View File
@@ -0,0 +1,467 @@
{
"registry": {
"strings": [
"StorageAndEnv",
"app",
"__ink_private",
"__ink_storage",
"__storage",
"Storage",
"value",
"Value",
"ink_core",
"storage",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"name",
"vec",
"Vec",
"elems",
"__env",
"EnvAccess",
"env2",
"env_access",
"immutable",
"TestEnv",
"test",
"accessor",
"DefaultSrmlTypes",
"types",
"access",
"EnvAccessMut",
"mutable",
"env",
"PhantomData",
"buffer",
"has_interacted",
"has_returned_value",
"new",
"init_value",
"bool",
"default",
"flip",
"get"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
2,
3,
4
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 5,
"type": 2
},
{
"name": 20,
"type": 14
}
]
}
},
{
"id": {
"custom.name": 6,
"custom.namespace": [
2,
2,
3,
4
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 7,
"type": 3
},
{
"name": 16,
"type": 9
}
]
}
},
{
"id": {
"custom.name": 8,
"custom.namespace": [
9,
10,
7
],
"custom.params": [
4
]
},
"def": {
"struct.fields": [
{
"name": 11,
"type": 5
}
]
}
},
{
"id": "bool",
"def": "builtin"
},
{
"id": {
"custom.name": 12,
"custom.namespace": [
9,
10,
11,
13
],
"custom.params": [
4
]
},
"def": {
"struct.fields": [
{
"name": 11,
"type": 6
}
]
}
},
{
"id": {
"custom.name": 14,
"custom.namespace": [
9,
10,
15
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
7
]
}
},
{
"id": {
"array.len": 32,
"array.type": 8
},
"def": "builtin"
},
{
"id": "u8",
"def": "builtin"
},
{
"id": {
"custom.name": 8,
"custom.namespace": [
9,
10,
7
],
"custom.params": [
10
]
},
"def": {
"struct.fields": [
{
"name": 11,
"type": 13
}
]
}
},
{
"id": "str",
"def": {
"struct.fields": [
{
"name": 17,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 18,
"custom.namespace": [],
"custom.params": [
8
]
},
"def": {
"struct.fields": [
{
"name": 19,
"type": 12
}
]
}
},
{
"id": {
"slice.type": 8
},
"def": "builtin"
},
{
"id": {
"custom.name": 12,
"custom.namespace": [
9,
10,
11,
13
],
"custom.params": [
10
]
},
"def": {
"struct.fields": [
{
"name": 11,
"type": 6
}
]
}
},
{
"id": {
"custom.name": 21,
"custom.namespace": [
9,
22,
23,
24
],
"custom.params": [
15
]
},
"def": {
"struct.fields": [
{
"name": 30,
"type": 17
}
]
}
},
{
"id": {
"custom.name": 25,
"custom.namespace": [
9,
22,
26,
27
],
"custom.params": [
16
]
},
"def": {
"struct.fields": []
}
},
{
"id": {
"custom.name": 28,
"custom.namespace": [
9,
22,
29
],
"custom.params": []
},
"def": {
"clike_enum.variants": []
}
},
{
"id": {
"custom.name": 31,
"custom.namespace": [
9,
22,
23,
32
],
"custom.params": [
15
]
},
"def": {
"struct.fields": [
{
"name": 33,
"type": 18
},
{
"name": 35,
"type": 11
},
{
"name": 36,
"type": 4
},
{
"name": 37,
"type": 4
}
]
}
},
{
"id": {
"custom.name": 34,
"custom.namespace": [],
"custom.params": [
15
]
},
"def": {
"tuple_struct.types": []
}
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 10,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 7,
"layout": {
"struct.type": 3,
"struct.fields": [
{
"name": 11,
"layout": {
"range.offset": "0x0000000000000000000000000000000000000000000000000000000000000000",
"range.len": 1,
"range.elem_type": 4
}
}
]
}
},
{
"name": 16,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 11,
"layout": {
"range.offset": "0x0000000000000000000000000000000000000000000000000000000000000001",
"range.len": 1,
"range.elem_type": 10
}
}
]
}
}
]
}
}
]
},
"contract": {
"name": 2,
"constructors": [
{
"name": 38,
"selector": "[\"0x5E\",\"0xBD\",\"0x88\",\"0xD6\"]",
"args": [
{
"name": 16,
"type": {
"ty": 11,
"display_name": [
18
]
}
},
{
"name": 39,
"type": {
"ty": 4,
"display_name": [
40
]
}
}
],
"docs": [
"Constructor that initializes the `bool` value to the given `init_value`."
]
},
{
"name": 41,
"selector": "[\"0x02\",\"0x22\",\"0xFF\",\"0x18\"]",
"args": [],
"docs": [
"Constructor that initializes the `bool` value to `false`.",
"",
"Constructors can delegate to other constructors."
]
}
],
"messages": [
{
"name": 42,
"selector": "[\"0x8C\",\"0x97\",\"0xDB\",\"0x39\"]",
"mutates": true,
"args": [],
"return_type": null,
"docs": [
"A message that can be called on instantiated contracts.",
"This one flips the value of the stored `bool` from `true`",
"to `false` and vice versa."
]
},
{
"name": 43,
"selector": "[\"0x25\",\"0x44\",\"0x4A\",\"0xFE\"]",
"mutates": false,
"args": [],
"return_type": {
"ty": 4,
"display_name": [
40
]
},
"docs": [
"Simply returns the current value of our `bool`."
]
}
],
"events": [],
"docs": []
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,188 @@
[
{
"info": 9,
"type": "{ \"value\": \"{ \"cell\": \"{ \"cell\": \"([u8;32])\"} }<u32>\"} }<u32>\"} }",
"sub": [
{
"info": 9,
"type": "{ \"cell\": \"{ \"cell\": \"([u8;32])\"} }<u32>\"} }",
"sub": [
{
"info": 9,
"type": "{ \"cell\": \"([u8;32])\"} }",
"sub": [
{
"info": 10,
"type": "([u8;32])",
"sub": [
{
"info": 12,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": "u8"
},
"sub": {
"info": 6,
"type": "u8"
},
"index": 0
}
],
"name": "cell",
"namespace": "ink_core::storage::key"
}
],
"name": "cell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 6,
"type": "u32"
}
]
}
],
"name": "value",
"namespace": "ink_core::storage::value",
"params": [
{
"info": 6,
"type": "u32"
}
]
}
],
"name": "Incrementer",
"namespace": "incrementer::normal"
},
{
"info": 9,
"type": "{ \"cell\": \"{ \"cell\": \"([u8;32])\"} }<u32>\"} }",
"sub": [
{
"info": 9,
"type": "{ \"cell\": \"([u8;32])\"} }",
"sub": [
{
"info": 10,
"type": "([u8;32])",
"sub": [
{
"info": 12,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": "u8"
},
"sub": {
"info": 6,
"type": "u8"
},
"index": 0
}
],
"name": "cell",
"namespace": "ink_core::storage::key"
}
],
"name": "cell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 6,
"type": "u32"
}
]
}
],
"name": "Value",
"namespace": "ink_core::storage::value",
"params": [
{
"info": 6,
"type": "u32"
}
]
},
{
"info": 6,
"type": "u32"
},
{
"info": 9,
"type": "{ \"cell\": \"([u8;32])\"} }",
"sub": [
{
"info": 10,
"type": "([u8;32])",
"sub": [
{
"info": 12,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": "u8"
},
"sub": {
"info": 6,
"type": "u8"
},
"index": 0
}
],
"name": "cell",
"namespace": "ink_core::storage::key"
}
],
"name": "SyncCell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 6,
"type": "u32"
}
]
},
{
"info": 10,
"type": "([u8;32])",
"sub": [
{
"info": 12,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": "u8"
},
"sub": {
"info": 6,
"type": "u8"
},
"index": 0
}
],
"name": "Key",
"namespace": "ink_core::storage::key"
},
{
"info": 12,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": "u8"
},
"sub": {
"info": 6,
"type": "u8"
}
},
{
"info": 6,
"type": "u8"
},
{
"info": 6,
"type": "bool"
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
{"name":"Incrementer","deploy":{"args":[{"name":"init_value","type":"u32"}]},"messages":[{"name":"inc","selector":257544423,"mutates":true,"args":[{"name":"by","type":"u32"}],"return_type":null},{"name":"get","selector":4266279973,"mutates":false,"args":[],"return_type":"u32"},{"name":"compare","selector":363906316,"mutates":false,"args":[{"name":"with","type":"u32"}],"return_type":"bool"}]}
@@ -0,0 +1,233 @@
{
"registry": {
"strings": [
"Incrementer",
"incrementer",
"normal",
"value",
"Value",
"ink_core",
"storage",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"on_deploy",
"init_value",
"u32",
"inc",
"by",
"get",
"compare",
"with",
"bool"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
3
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 4,
"type": 2
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
4
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 8,
"type": 4
}
]
}
},
{
"id": "u32",
"def": "builtin"
},
{
"id": {
"custom.name": 9,
"custom.namespace": [
6,
7,
8,
10
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 8,
"type": 5
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
12
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
6
]
}
},
{
"id": {
"array.len": 32,
"array.type": 7
},
"def": "builtin"
},
{
"id": "u8",
"def": "builtin"
},
{
"id": "bool",
"def": "builtin"
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 8,
"layout": {
"range.offset": "0x0000000000000000000000000000000000000000000000000000000000000000",
"range.len": 1,
"range.elem_type": 3
}
}
]
}
}
]
},
"contract": {
"name": 1,
"constructors": [
{
"name": 13,
"selector": "[\"0x00\",\"0x00\",\"0x00\",\"0x00\"]",
"args": [
{
"name": 14,
"type": {
"ty": 3,
"display_name": [
15
]
}
}
],
"docs": [
"Initializes the value to the initial value."
]
}
],
"messages": [
{
"name": 16,
"selector": "[\"0x0F\",\"0x59\",\"0xD0\",\"0xE7\"]",
"mutates": true,
"args": [
{
"name": 17,
"type": {
"ty": 3,
"display_name": [
15
]
}
}
],
"return_type": null,
"docs": [
"Flips the current state of our smart contract."
]
},
{
"name": 18,
"selector": "[\"0xFE\",\"0x4A\",\"0x44\",\"0x25\"]",
"mutates": false,
"args": [],
"return_type": {
"ty": 3,
"display_name": [
15
]
},
"docs": [
"Returns the current state."
]
},
{
"name": 19,
"selector": "[\"0x15\",\"0xB0\",\"0xC5\",\"0x0C\"]",
"mutates": false,
"args": [
{
"name": 20,
"type": {
"ty": 3,
"display_name": [
15
]
}
}
],
"return_type": {
"ty": 8,
"display_name": [
21
]
},
"docs": [
"Returns `true` if the internal value is greater than or equal to the provided value."
]
}
],
"events": [],
"docs": []
}
}
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-derive",
"version": "0.95.2",
"version": "0.97.1",
"description": "Common functions used across Polkadot, derived from RPC calls and storage queries.",
"main": "index.js",
"keywords": [
@@ -27,11 +27,11 @@
},
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-derive#readme",
"dependencies": {
"@babel/runtime": "^7.6.3",
"@polkadot/api": "^0.95.2",
"@polkadot/types": "^0.95.2"
"@babel/runtime": "^7.7.4",
"@polkadot/api": "^0.97.1",
"@polkadot/types": "^0.97.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.6.1"
"@polkadot/keyring": "^1.7.1"
}
}
+31 -33
View File
@@ -5,17 +5,41 @@
import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces';
import { Observable, of } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { createType } from '@polkadot/types';
import { isU8a } from '@polkadot/util';
import { decodeAddress } from '@polkadot/util-crypto';
import { createType } from '@polkadot/types';
import { idToIndex } from './idToIndex';
import { indexToId } from './indexToId';
import { drr } from '../util/drr';
import { memo } from '../util';
export type AccountIdAndIndex = [AccountId?, AccountIndex?];
function retrieve (api: ApiInterfaceRx, address: Address | AccountId | AccountIndex | string | null | undefined): Observable<AccountIdAndIndex> {
try {
// yes, this can fail, don't care too much, catch will catch it
const decoded = isU8a(address)
? address
: decodeAddress((address || '').toString());
if (decoded.length === 32) {
const accountId = createType(api.registry, 'AccountId', decoded);
return api.derive.accounts.idToIndex(accountId).pipe(
map((accountIndex): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex)
);
}
const accountIndex = createType(api.registry, 'AccountIndex', decoded);
return api.derive.accounts.indexToId(accountIndex).pipe(
map((accountId): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex)
);
} catch (error) {
return of([undefined, undefined] as AccountIdAndIndex);
}
}
/**
* @name idAndIndex
* @param {(Address | AccountId | AccountIndex | string | null)} address - An accounts address in various formats.
@@ -30,32 +54,6 @@ export type AccountIdAndIndex = [AccountId?, AccountIndex?];
* ```
*/
export function idAndIndex (api: ApiInterfaceRx): (address?: Address | AccountId | AccountIndex | string | null) => Observable<AccountIdAndIndex> {
return (address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> => {
try {
// yes, this can fail, don't care too much, catch will catch it
const decoded = isU8a(address)
? address
: decodeAddress((address || '').toString());
if (decoded.length === 32) {
const accountId = createType('AccountId', decoded);
return idToIndex(api)(accountId).pipe(
startWith(undefined),
map((accountIndex): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex),
drr()
);
}
const accountIndex = createType('AccountIndex', decoded);
return indexToId(api)(accountIndex).pipe(
startWith(undefined),
map((accountId): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex),
drr()
);
} catch (error) {
return of([undefined, undefined] as AccountIdAndIndex).pipe(drr());
}
};
return memo((address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> =>
retrieve(api, address));
}
+9 -11
View File
@@ -3,13 +3,13 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, AccountIndex } from '@polkadot/types/interfaces';
import { AccountIndexes } from '../types';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { indexes, AccountIndexes } from './indexes';
import { drr } from '../util/drr';
import { memo } from '../util';
/**
* @name idToIndex
@@ -26,13 +26,11 @@ import { drr } from '../util/drr';
* ```
*/
export function idToIndex (api: ApiInterfaceRx): (accountId: AccountId | string) => Observable<AccountIndex | undefined> {
return (accountId: AccountId | string): Observable<AccountIndex | undefined> =>
indexes(api)()
.pipe(
startWith({}),
map((indexes: AccountIndexes): AccountIndex | undefined =>
(indexes || {})[accountId.toString()]
),
drr()
);
return memo((accountId: AccountId | string): Observable<AccountIndex | undefined> =>
api.derive.accounts.indexes().pipe(
startWith({}),
map((indexes: AccountIndexes): AccountIndex | undefined =>
(indexes || {})[accountId.toString()]
)
));
}
@@ -6,3 +6,4 @@ export * from './idAndIndex';
export * from './idToIndex';
export * from './indexToId';
export * from './indexes';
export * from './info';
+15 -16
View File
@@ -8,9 +8,9 @@ import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex';
import { createType, ClassOf, Vec } from '@polkadot/types';
import { ClassOf, Vec, createType } from '@polkadot/types';
import { drr } from '../util/drr';
import { memo } from '../util';
/**
* @name indexToId
@@ -26,19 +26,18 @@ import { drr } from '../util/drr';
* ```
*/
export function indexToId (api: ApiInterfaceRx): (accountIndex: AccountIndex | string) => Observable<AccountId | undefined> {
return (_accountIndex: AccountIndex | string): Observable<AccountId | undefined> => {
const querySection = api.query.indices || api.query.balances;
const accountIndex = _accountIndex instanceof ClassOf('AccountIndex')
? _accountIndex
: createType('AccountIndex', _accountIndex);
const querySection = api.query.indices || api.query.balances;
return (querySection.enumSet<Vec<AccountId>>(accountIndex.div(ENUMSET_SIZE)))
.pipe(
startWith([]),
map((accounts): AccountId | undefined =>
(accounts || [])[accountIndex.mod(ENUMSET_SIZE).toNumber()]
),
drr()
);
};
return memo((_accountIndex: AccountIndex | string): Observable<AccountId | undefined> => {
const accountIndex = _accountIndex instanceof ClassOf(api.registry, 'AccountIndex')
? _accountIndex
: createType(api.registry, 'AccountIndex', _accountIndex);
return querySection.enumSet<Vec<AccountId>>(accountIndex.div(ENUMSET_SIZE)).pipe(
startWith([]),
map((accounts): AccountId | undefined =>
(accounts || [])[accountIndex.mod(ENUMSET_SIZE).toNumber()]
)
);
});
}
+24 -28
View File
@@ -2,17 +2,16 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, AccountIndex } from '@polkadot/types/interfaces';
import { AccountIndexes } from '../types';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex';
import { createType } from '@polkadot/types';
import { Vec, createType } from '@polkadot/types';
import { drr } from '../util/drr';
export type AccountIndexes = Record<string, AccountIndex>;
import { memo } from '../util';
const enumsetSize = ENUMSET_SIZE.toNumber();
@@ -32,29 +31,26 @@ const enumsetSize = ENUMSET_SIZE.toNumber();
* ```
*/
export function indexes (api: ApiInterfaceRx): () => Observable<AccountIndexes> {
return (): Observable<AccountIndexes> => {
return (api.query.indices.nextEnumSet<AccountIndex>())
.pipe(
// use the nextEnumSet (which is a counter of the number of sets) to construct
// a range of values to query [0, 1, 2, ...]. Retrieve the full enum set for the
// specific index - each query can return up to ENUMSET_SIZE (64) records, each
// containing an AccountId
switchMap((next: AccountIndex): Observable<any> =>
api.query.indices.enumSet.multi([...Array(next.toNumber() + 1).keys()]) as Observable<any>
),
map((all: (AccountId[] | undefined)[]): AccountIndexes =>
(all || []).reduce((result, list, outerIndex): AccountIndexes => {
(list || []).forEach((accountId, innerIndex): void => {
// re-create the index based on position 0 is [0][0] and likewise
// 64 (0..63 in first) is [1][0] (the first index value in set 2)
const index = (outerIndex * enumsetSize) + innerIndex;
return memo((): Observable<AccountIndexes> =>
api.query.indices.nextEnumSet<AccountIndex>().pipe(
// use the nextEnumSet (which is a counter of the number of sets) to construct
// a range of values to query [0, 1, 2, ...]. Retrieve the full enum set for the
// specific index - each query can return up to ENUMSET_SIZE (64) records, each
// containing an AccountId
switchMap((next: AccountIndex): Observable<Vec<AccountId>[]> =>
api.query.indices.enumSet.multi<Vec<AccountId>>([...Array(next.toNumber() + 1).keys()])
),
map((all: AccountId[][]): AccountIndexes =>
all.reduce((result: AccountIndexes, list, outerIndex): AccountIndexes => {
(list || []).forEach((accountId, innerIndex): void => {
// re-create the index based on position 0 is [0][0] and likewise
// 64 (0..63 in first) is [1][0] (the first index value in set 2)
const index = (outerIndex * enumsetSize) + innerIndex;
result[accountId.toString()] = createType('AccountIndex', index);
});
result[accountId.toString()] = createType(api.registry, 'AccountIndex', index);
});
return result;
}, {} as AccountIndexes)),
drr()
);
};
return result;
}, {}))
));
}
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, AccountIndex, Address, Balance } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DeriveAccountInfo } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Bytes, Option, u32 } from '@polkadot/types';
import { u8aToString } from '@polkadot/util';
import { memo } from '../util';
function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable<string | undefined> {
return ((
accountId && api.query.nicks
? api.query.nicks.nameOf<Option<ITuple<[Bytes, Balance]>>>(accountId)
: of(undefined)
) as Observable<Option<ITuple<[Bytes, Balance]>> | undefined>).pipe(
map((nameOf): string | undefined =>
nameOf?.isSome
? u8aToString(nameOf.unwrap()[0]).substr(0, (api.consts.nicks.maxLength as u32).toNumber())
: undefined
)
);
}
/**
* @name info
* @description Returns aux. info with regards to an account, current that includes the accountId, accountIndex and nickname
*/
export function info (api: ApiInterfaceRx): (address?: AccountIndex | AccountId | Address | string | null) => Observable<DeriveAccountInfo> {
return memo((address?: AccountIndex | AccountId | Address | string | null): Observable<DeriveAccountInfo> =>
api.derive.accounts.idAndIndex(address).pipe(
switchMap(([accountId, accountIndex]): Observable<[DeriveAccountInfo, string?]> =>
combineLatest([
of({ accountId, accountIndex }),
retrieveNick(api, accountId)
])
),
map(([{ accountId, accountIndex }, nickname]): DeriveAccountInfo => ({
accountId, accountIndex, nickname
}))
));
}
+35 -32
View File
@@ -3,6 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, AccountIndex, Address, Balance, BalanceLock, BlockNumber, Index, VestingSchedule } from '@polkadot/types/interfaces';
import { DerivedBalances } from '../types';
import BN from 'bn.js';
import { combineLatest, of, Observable } from 'rxjs';
@@ -11,50 +12,54 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, Vec, createType } from '@polkadot/types';
import { bnMax } from '@polkadot/util';
import { idAndIndex } from '../accounts/idAndIndex';
import { bestNumber } from '../chain/bestNumber';
import { DerivedBalances } from '../types';
import { drr } from '../util/drr';
import { memo } from '../util';
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>];
type Result = [AccountId, BlockNumber, ResultBalance, Index];
function calcBalances ([accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances {
let lockedBalance = createType('Balance');
function calcBalances (api: ApiInterfaceRx, [accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances {
let lockedBalance = createType(api.registry, 'Balance');
let lockedBreakdown: BalanceLock[] = [];
if (Array.isArray(locks)) {
// only get the locks that are valid until passed the current block
const totals = locks.filter((value): boolean => bestNumber && value.until.gt(bestNumber));
lockedBreakdown = locks.filter(({ until }): boolean => bestNumber && until.gt(bestNumber));
// get the maximum of the locks according to https://github.com/paritytech/substrate/blob/master/srml/balances/src/lib.rs#L699
lockedBalance = totals[0]
? createType('Balance', bnMax(...totals.map(({ amount }): Balance => amount)))
: createType('Balance');
if (lockedBreakdown.length) {
lockedBalance = createType(api.registry, 'Balance', bnMax(...lockedBreakdown.map(({ amount }): Balance => amount)));
}
}
// offset = balance locked at genesis, perBlock is the unlock amount
const { offset, perBlock } = vesting.unwrapOr(createType('VestingSchedule'));
const vestedNow = createType('Balance', perBlock.mul(bestNumber));
const vestedBalance = vestedNow.gt(offset)
? freeBalance
: createType('Balance', freeBalance.sub(offset).add(vestedNow));
// Calculate the vesting balances,
// - offset = balance locked at genesis,
// - perBlock is the unlock amount
const { offset: vestingTotal, perBlock } = vesting.unwrapOr(createType(api.registry, 'VestingSchedule'));
const vestedBalance = createType(api.registry, 'Balance', perBlock.mul(bestNumber));
const isVesting = vestedBalance.lt(vestingTotal);
// NOTE Workaround for this account on Alex (one of a couple reported) -
// 5F7BJL6Z4m8RLtK7nXEqqpEqhBbd535Z3CZeYF6ccvaQAY6N
// The locked is > the vested and ended up with the locked > free,
// i.e. related to https://github.com/paritytech/polkadot/issues/225
// (most probably due to movements from stash -> controller -> free)
const availableBalance = createType('Balance', bnMax(new BN(0), vestedBalance.sub(lockedBalance)));
// The available balance & vested has an interplay here
// "
// vesting is a guarantee that the account's balance will never go below a certain amount. so it functions in the opposite way, a bit like a lock that is monotonically decreasing rather than a liquid amount that is monotonically increasing.
// locks function as the same guarantee - that a balance will not be lower than a particular amount.
// because of this you can see that if there is a "vesting lock" that guarantees the balance cannot go below 200, and a "staking lock" that guarantees the balance cannot drop below 300, then we just have two guarantees of which the first is irrelevant.
// i.e. (balance >= 200 && balance >= 300) == (balance >= 300)
// ""
const floating = freeBalance.sub(lockedBalance);
const availableBalance = createType(api.registry, 'Balance', bnMax(new BN(0), isVesting && floating.gt(vestedBalance) ? vestedBalance : floating));
return {
accountId,
accountNonce,
availableBalance,
freeBalance,
isVesting,
lockedBalance,
lockedBreakdown,
reservedBalance,
vestedBalance,
votingBalance: createType('Balance', freeBalance.add(reservedBalance))
vestingTotal,
votingBalance: createType(api.registry, 'Balance', freeBalance.add(reservedBalance))
};
}
@@ -83,13 +88,13 @@ function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable<R
* ```
*/
export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId | Address | string) => Observable<DerivedBalances> {
return (address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> => {
return idAndIndex(api)(address).pipe(
switchMap(([accountId]): Observable<Result> =>
return memo((address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> =>
api.derive.accounts.info(address).pipe(
switchMap(({ accountId }): Observable<Result> =>
(accountId
? combineLatest([
of(accountId),
bestNumber(api)(),
api.derive.chain.bestNumber(),
queryBalances(api, accountId),
// FIXME This is having issues with Kusama, only use accountNonce atm
// api.rpc.account && api.rpc.account.nextIndex
@@ -98,11 +103,9 @@ export function all (api: ApiInterfaceRx): (address: AccountIndex | AccountId |
// : api.query.system.accountNonce<Index>(accountId)
api.query.system.accountNonce<Index>(accountId)
])
: of([createType('AccountId'), createType('BlockNumber'), [createType('Balance'), createType('Balance'), createType('Vec<BalanceLock>'), createType('Option<VestingSchedule>', null)], createType('Index')])
: of([createType(api.registry, 'AccountId'), createType(api.registry, 'BlockNumber'), [createType(api.registry, 'Balance'), createType(api.registry, 'Balance'), createType(api.registry, 'Vec<BalanceLock>'), createType(api.registry, 'Option<VestingSchedule>', null)], createType(api.registry, 'Index')])
)
),
map(calcBalances),
drr()
);
};
map((result): DerivedBalances => calcBalances(api, result))
));
}
+12 -14
View File
@@ -9,7 +9,7 @@ import { DerivedFees } from '../types';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr } from '../util/drr';
import { memo } from '../util';
type Result = [Balance, Balance, Balance, Balance, Balance];
@@ -19,9 +19,9 @@ function queryV2 (api: ApiInterfaceRx): Observable<Result> {
return of([
// get values from api.const for substrate versions post spec_version: 101
// https://github.com/paritytech/substrate/pull/2883/files#diff-5e5e1c3aec9ddfde0a9054d062ab3db9R131
api.consts.balances.creationFee as Balance,
api.consts.balances.existentialDeposit as Balance,
api.consts.balances.transferFee as Balance,
api.consts.balances.creationFee,
api.consts.balances.existentialDeposit,
api.consts.balances.transferFee,
paymentBase.transactionBaseFee as Balance,
paymentBase.transactionByteFee as Balance
]);
@@ -52,20 +52,18 @@ function queryV1 (api: ApiInterfaceRx): Observable<Result> {
* ```
*/
export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
return (): Observable<DerivedFees> => {
return (
api.consts.balances
? queryV2(api)
: queryV1(api)
).pipe(
const query = api.consts.balances
? queryV2
: queryV1;
return memo((): Observable<DerivedFees> =>
query(api).pipe(
map(([creationFee, existentialDeposit, transferFee, transactionBaseFee, transactionByteFee]): DerivedFees => ({
creationFee,
existentialDeposit,
transactionBaseFee,
transactionByteFee,
transferFee
})),
drr()
);
};
}))
));
}
@@ -3,22 +3,20 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces';
import { DerivedBalances } from '../types';
import { combineLatest, Observable, of } from 'rxjs';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedBalances } from '../types';
import { drr } from '../util/drr';
import { all } from './all';
import { memo } from '../util';
export function votingBalances (api: ApiInterfaceRx): (addresses?: (AccountId | AccountIndex | Address | string)[]) => Observable<DerivedBalances[]> {
return (addresses?: (AccountId | AccountIndex | Address | string)[]): Observable<DerivedBalances[]> => {
return (
!addresses || !addresses.length
? of([] as DerivedBalances[])
: combineLatest(addresses.map(all(api)))
).pipe(
drr()
);
};
return memo((addresses?: (AccountId | AccountIndex | Address | string)[]): Observable<DerivedBalances[]> =>
!addresses || !addresses.length
? of([] as DerivedBalances[])
: combineLatest(
addresses.map((accountId): Observable<DerivedBalances> =>
api.derive.balances.all(accountId))
)
);
}
@@ -3,27 +3,25 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, AccountIndex, Address } from '@polkadot/types/interfaces';
import { DerivedBalances } from '../types';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec } from '@polkadot/types';
import { idAndIndex } from '../accounts/idAndIndex';
import { DerivedBalances } from '../types';
import { drr } from '../util/drr';
import { votingBalances } from './votingBalances';
import { memo } from '../util';
export function votingBalancesNominatorsFor (api: ApiInterfaceRx): (address: AccountId | AccountIndex | Address | string) => Observable<DerivedBalances[]> {
return (address: AccountId | AccountIndex | Address | string): Observable<DerivedBalances[]> => {
return idAndIndex(api)(address).pipe(
switchMap(([accountId]): Observable<AccountId[]> =>
return memo((address: AccountId | AccountIndex | Address | string): Observable<DerivedBalances[]> =>
api.derive.accounts.info(address).pipe(
switchMap(({ accountId }): Observable<AccountId[]> =>
accountId
? (api.query.staking.nominatorsFor<Vec<AccountId>>(accountId))
? api.query.staking.nominatorsFor<Vec<AccountId>>(accountId)
: of([] as AccountId[])
),
switchMap(votingBalances(api)),
drr()
);
};
switchMap((accounts): Observable<DerivedBalances[]> =>
api.derive.balances.votingBalances(accounts)
)
));
}
+6 -7
View File
@@ -2,13 +2,13 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { BlockNumber } from '@polkadot/types/interfaces';
import { BlockNumber, Header } from '@polkadot/types/interfaces';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util/drr';
import { memo } from '../util';
/**
* @name bestNumber
@@ -23,9 +23,8 @@ import { drr } from '../util/drr';
* ```
*/
export function bestNumber (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
api.rpc.chain.subscribeNewHeads().pipe(
map((header): BlockNumber => header.number.unwrap()),
drr()
);
return memo((): Observable<BlockNumber> =>
api.derive.chain.subscribeNewHeads().pipe(
map((header: Header): BlockNumber => header.number.unwrap())
));
}
@@ -8,7 +8,7 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util/drr';
import { memo } from '../util';
/**
* @name bestNumberFinalized
@@ -24,9 +24,8 @@ import { drr } from '../util/drr';
* ```
*/
export function bestNumberFinalized (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
return memo((): Observable<BlockNumber> =>
api.rpc.chain.subscribeFinalizedHeads().pipe(
map((header): BlockNumber => header.number.unwrap()),
drr()
);
map((header): BlockNumber => header.number.unwrap())
));
}
+7 -10
View File
@@ -9,9 +9,7 @@ import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { createType } from '@polkadot/types';
import { drr } from '../util/drr';
import { bestNumber } from './bestNumber';
import { bestNumberFinalized } from './bestNumberFinalized';
import { memo } from '../util';
/**
* @name bestNumberLag
@@ -27,14 +25,13 @@ import { bestNumberFinalized } from './bestNumberFinalized';
* ```
*/
export function bestNumberLag (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
return memo((): Observable<BlockNumber> =>
combineLatest([
bestNumber(api)(),
bestNumberFinalized(api)()
api.derive.chain.bestNumber(),
api.derive.chain.bestNumberFinalized()
]).pipe(
map(([bestNumber, bestNumberFinalized]): BlockNumber =>
createType('BlockNumber', bestNumber.sub(bestNumberFinalized))
),
drr()
);
createType(api.registry, 'BlockNumber', bestNumber.sub(bestNumberFinalized))
)
));
}
+14 -12
View File
@@ -2,13 +2,16 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Observable, combineLatest, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AccountId } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Observable, combineLatest, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Vec } from '@polkadot/types';
import { HeaderExtended } from '../type';
import { drr } from '../util/drr';
import { HeaderAndValidators } from './subscribeNewHeads';
import { memo } from '../util';
/**
* @name bestNumberFinalized
@@ -25,22 +28,21 @@ import { HeaderAndValidators } from './subscribeNewHeads';
* ```
*/
export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) => Observable<HeaderExtended | undefined> {
return (hash: Uint8Array | string): Observable<HeaderExtended | undefined> =>
(combineLatest([
return memo((hash: Uint8Array | string): Observable<HeaderExtended | undefined> =>
combineLatest([
api.rpc.chain.getHeader(hash),
api.query.session
? api.query.session.validators.at(hash)
? api.query.session.validators.at(hash) as Observable<Vec<AccountId>>
: of([])
]) as Observable<HeaderAndValidators>).pipe(
]).pipe(
map(([header, validators]): HeaderExtended =>
new HeaderExtended(header, validators)
new HeaderExtended(api.registry, header, validators)
),
catchError((): Observable<undefined> =>
// where rpc.chain.getHeader throws, we will land here - it can happen that
// we supplied an invalid hash. (Due to defaults, storeage will have an
// empty value, so only the RPC is affected). So return undefined
of()
),
drr()
);
)
));
}
@@ -3,15 +3,12 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, Header } from '@polkadot/types/interfaces';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { HeaderExtended } from '../type';
import { drr } from '../util/drr';
export type HeaderAndValidators = [Header, AccountId[]];
import { memo } from '../util';
/**
* @name subscribeNewHeads
@@ -27,22 +24,13 @@ export type HeaderAndValidators = [Header, AccountId[]];
* ```
*/
export function subscribeNewHeads (api: ApiInterfaceRx): () => Observable<HeaderExtended> {
return (): Observable<HeaderExtended> =>
api.rpc.chain.subscribeNewHeads().pipe(
switchMap((header: Header): Observable<HeaderAndValidators> =>
(combineLatest([
of(header),
// theoretically we could combine at the first call with session.validators(), however
// we make 100% sure we actually get the validators at a specific block so when these
// change at an era boundary, we have the previous values to ensure our indexes are correct
api.query.session
? api.query.session.validators.at(header.hash)
: of([])
]) as Observable<HeaderAndValidators>)
),
map(([header, validators]): HeaderExtended =>
new HeaderExtended(header, validators)
),
drr()
);
return memo((): Observable<HeaderExtended> =>
combineLatest([
api.rpc.chain.subscribeNewHeads(),
api.derive.staking.validators()
]).pipe(
map(([header, { validators }]): HeaderExtended =>
new HeaderExtended(api.registry, header, validators)
)
));
}
+5 -53
View File
@@ -9,7 +9,7 @@ import BN from 'bn.js';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr } from '../util/drr';
import { memo } from '../util';
type ResultV2 = [BN, BN, BN, BN, BN, BN, BN, BN, BN, BN];
@@ -31,49 +31,6 @@ function parseResult ([callBaseFee, contractFee, createBaseFee, creationFee, ren
};
}
// Only for 1.0 support. rentByteFee, rentDepositOffset, tombstoneDeposit are not available in substrate 1.0.
// TODO remove this once 1.0 support is dropped
function queryV1 (api: ApiInterfaceRx): Observable<DerivedContractFees> {
return (
api.queryMulti([
api.query.contract.callBaseFee,
api.query.contract.contractFee,
api.query.contract.createBaseFee,
api.query.contract.creationFee,
api.query.contract.transactionBaseFee,
api.query.contract.transactionByteFee,
api.query.contract.transferFee
]) as unknown as Observable<BN[]>
).pipe(
map(([callBaseFee, contractFee, createBaseFee, creationFee, transactionBaseFee, transactionByteFee, transferFee]): DerivedContractFees =>
// We've done this on purpose, i.e. so we can just copy the name/order from the parse above and
// see gaps, in this case those are filled with `ZERO`
parseResult([
callBaseFee, contractFee, createBaseFee, creationFee, ZERO, ZERO, ZERO, transactionBaseFee, transactionByteFee, transferFee
])
),
drr()
);
}
// query via query (early v2, non-current, support to be dropped])
function queryQuery (api: ApiInterfaceRx): Observable<ResultV2> {
const queryBase = api.query.contracts || api.query.contract;
return api.queryMulti([
queryBase.callBaseFee,
queryBase.contractFee,
queryBase.createBaseFee,
queryBase.creationFee,
queryBase.rentByteFee,
queryBase.rentDepositOffset,
queryBase.tombstoneDeposit,
queryBase.transactionBaseFee,
queryBase.transactionByteFee,
queryBase.transferFee
]) as unknown as Observable<ResultV2>;
}
// query via constants (current applicable path)
function queryConstants (api: ApiInterfaceRx): Observable<ResultV2> {
return of([
@@ -104,23 +61,18 @@ function queryConstants (api: ApiInterfaceRx): Observable<ResultV2> {
* ```
*/
export function fees (api: ApiInterfaceRx): () => Observable<DerivedContractFees> {
return (): Observable<DerivedContractFees> => {
if (api.query.contract && !api.query.contract.rentByteFee) {
return queryV1(api);
}
return memo((): Observable<DerivedContractFees> => {
return (
api.consts.contracts
? queryConstants(api)
: queryQuery(api)
: of([ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO])
).pipe(
map(([callBaseFee, contractFee, createBaseFee, creationFee, rentByteFee, rentDepositOffset, tombstoneDeposit, transactionBaseFee, transactionByteFee, transferFee]): DerivedContractFees =>
// We've done this on purpose, i.e. so we can just copy the name/order from the parse above and see gaps
parseResult([
callBaseFee, contractFee, createBaseFee, creationFee, rentByteFee, rentDepositOffset, tombstoneDeposit, transactionBaseFee, transactionByteFee, transferFee
])
),
drr()
)
);
};
});
}
@@ -12,29 +12,27 @@ import { Option } from '@polkadot/types';
import { isNull } from '@polkadot/util';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util/drr';
import { memo } from '../util';
export function constructInfo (index: BN | number, optionInfo?: Option<ReferendumInfo>): Option<ReferendumInfoExtended> {
export function constructInfo (api: ApiInterfaceRx, index: BN | number, optionInfo?: Option<ReferendumInfo>): Option<ReferendumInfoExtended> {
const info = optionInfo
? optionInfo.unwrapOr(null)
: null;
return new Option<ReferendumInfoExtended>(
api.registry,
ReferendumInfoExtended,
isNull(info)
? null
: new ReferendumInfoExtended(info, index)
: new ReferendumInfoExtended(api.registry, info, index)
);
}
export function referendumInfo (api: ApiInterfaceRx): (index: BN | number) => Observable<Option<ReferendumInfoExtended>> {
return (index: BN | number): Observable<Option<ReferendumInfoExtended>> => {
return (api.query.democracy.referendumInfoOf<Option<ReferendumInfo>>(index))
.pipe(
map((optionInfo): Option<ReferendumInfoExtended> =>
constructInfo(index, optionInfo)
),
drr()
);
};
return memo((index: BN | number): Observable<Option<ReferendumInfoExtended>> =>
api.query.democracy.referendumInfoOf<Option<ReferendumInfo>>(index).pipe(
map((optionInfo): Option<ReferendumInfoExtended> =>
constructInfo(api, index, optionInfo)
)
));
}
@@ -11,22 +11,20 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, Vec } from '@polkadot/types';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util/drr';
import { memo } from '../util';
import { constructInfo } from './referendumInfo';
export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) => Observable<Option<ReferendumInfoExtended>[]> {
return (ids: (BN | number)[] = []): Observable<Option<ReferendumInfoExtended>[]> => {
return (
return memo((ids: (BN | number)[] = []): Observable<Option<ReferendumInfoExtended>[]> =>
(
!ids || !ids.length
? of([] as Option<ReferendumInfo>[])
: api.query.democracy.referendumInfoOf.multi(ids) as Observable<Vec<Option<ReferendumInfo>>>
).pipe(
map((infos): Option<ReferendumInfoExtended>[] =>
ids.map((id, index): Option<ReferendumInfoExtended> =>
constructInfo(id, infos[index])
constructInfo(api, id, infos[index])
)
),
drr()
);
};
)
));
}
@@ -11,27 +11,24 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec, createType } from '@polkadot/types';
import { DerivedBalances, DerivedReferendumVote } from '../types';
import { drr } from '../util/drr';
import { votes } from './votes';
import { votingBalances } from '../balances/votingBalances';
import { memo } from '../util';
export function referendumVotesFor (api: ApiInterfaceRx): (referendumId: BN | number) => Observable<DerivedReferendumVote[]> {
return (referendumId: BN | number): Observable<DerivedReferendumVote[]> =>
(api.query.democracy.votersFor<Vec<AccountId>>(referendumId)).pipe(
return memo((referendumId: BN | number): Observable<DerivedReferendumVote[]> =>
api.query.democracy.votersFor<Vec<AccountId>>(referendumId).pipe(
switchMap((votersFor): Observable<[Vec<AccountId>, Vote[], DerivedBalances[]]> =>
combineLatest([
of(votersFor),
votes(api)(referendumId as BN, votersFor),
votingBalances(api)(votersFor)
api.derive.democracy.votes(referendumId as BN, votersFor),
api.derive.balances.votingBalances(votersFor)
])
),
map(([votersFor, votes, balances]): DerivedReferendumVote[] =>
votersFor.map((accountId, index): DerivedReferendumVote => ({
accountId,
balance: balances[index].votingBalance || createType('Balance'),
vote: votes[index] || createType('Vote')
balance: balances[index].votingBalance || createType(api.registry, 'Balance'),
vote: votes[index] || createType(api.registry, 'Vote')
} as unknown as DerivedReferendumVote))
),
drr()
);
)
));
}
@@ -11,24 +11,22 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option } from '@polkadot/types';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util/drr';
import { referendumInfos } from './referendumInfos';
import { memo } from '../util';
export function referendums (api: ApiInterfaceRx): () => Observable<Option<ReferendumInfoExtended>[]> {
return (): Observable<Option<ReferendumInfoExtended>[]> =>
(api.queryMulti([
return memo((): Observable<Option<ReferendumInfoExtended>[]> =>
api.queryMulti<[ReferendumIndex, ReferendumIndex]>([
api.query.democracy.nextTally,
api.query.democracy.referendumCount
]) as Observable<[ReferendumIndex?, ReferendumIndex?]>).pipe(
]).pipe(
switchMap(([nextTally, referendumCount]): Observable<Option<ReferendumInfoExtended>[]> =>
referendumCount && nextTally && referendumCount.gt(nextTally) && referendumCount.gtn(0)
? referendumInfos(api)(
? api.derive.democracy.referendumInfos(
[...Array(referendumCount.sub(nextTally).toNumber())].map((_, i): BN =>
nextTally.addn(i)
)
)
: of([])
),
drr()
);
)
));
}
+9 -12
View File
@@ -7,20 +7,17 @@ import { AccountId, Vote } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { Observable, of } from 'rxjs';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec } from '@polkadot/types';
import { drr } from '../util/drr';
import { memo } from '../util';
export function votes (api: ApiInterfaceRx): (referendumId: BN, accountIds?: AccountId[]) => Observable<Vote[]> {
return (referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> => {
return ((
!accountIds || !accountIds.length
? of([])
: api.query.democracy.voteOf.multi(
accountIds.map((accountId): [BN, AccountId] =>
[referendumId, accountId]
)
return memo((referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> =>
!accountIds || !accountIds.length
? of([] as Vote[])
: api.query.democracy.voteOf.multi<Vote>(
accountIds.map((accountId): [BN, AccountId] =>
[referendumId, accountId]
)
) as Observable<Vec<Vote>>).pipe(drr());
};
)
);
}
@@ -5,11 +5,28 @@
import { AccountId, ApprovalFlag, SetIndex } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Observable } from 'rxjs';
import { Observable, of } from 'rxjs';
import { Vec } from '@polkadot/types';
import { switchMap, map } from 'rxjs/operators';
import { approvalFlagsToBools } from '../util/approvalFlagsToBools';
import { drr } from '../util/drr';
import { memo } from '../util';
function queryElections (api: ApiInterfaceRx, who: AccountId | string): Observable<boolean[][]> {
return api.query.elections.nextVoterSet<SetIndex>().pipe(
switchMap((nextVoterSet: SetIndex): Observable<Vec<ApprovalFlag>[]> =>
api.query.elections.approvalsOf.multi(
[...Array(nextVoterSet.toNumber() + 1).keys()].map((i): [string, number] =>
[who.toString(), i]
)
) as any as Observable<Vec<ApprovalFlag>[]>
),
map((votes: Vec<ApprovalFlag>[]): boolean[][] =>
votes.map((flags: Vec<ApprovalFlag>): boolean[] =>
approvalFlagsToBools(flags)
)
)
);
}
/**
* @name approvalsOf
@@ -23,21 +40,10 @@ import { drr } from '../util/drr';
* });
* ```
*/
export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observable<boolean[][]> {
return (who: AccountId | string): Observable<boolean[][]> =>
api.query.elections.nextVoterSet<SetIndex>().pipe(
switchMap((nextVoterSet: SetIndex): Observable<Vec<ApprovalFlag>[]> =>
api.query.elections.approvalsOf.multi(
[...Array(nextVoterSet.toNumber() + 1).keys()].map((i): [string, number] => [
who.toString(), i]
)
) as any as Observable<Vec<ApprovalFlag>[]>
),
map((votes: Vec<ApprovalFlag>[]): boolean[][] =>
votes.map((flags: Vec<ApprovalFlag>): boolean[] =>
approvalFlagsToBools(flags)
)
),
drr()
);
export function approvalsOf (api: ApiInterfaceRx): (who: AccountId | string) => Observable<boolean[][]> {
return memo((who: AccountId | string): Observable<boolean[][]> =>
api.query.elections
? queryElections(api, who)
: of([])
);
}
@@ -5,13 +5,19 @@
import { AccountId, ApprovalFlag, SetIndex } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec } from '@polkadot/types';
import { approvalFlagsToBools } from '../util/approvalFlagsToBools';
import { drr } from '../util/drr';
import { memo } from '../util';
function queryElections (api: ApiInterfaceRx, who: AccountId | string, at: SetIndex | BN | number): Observable<boolean[]> {
return api.query.elections.approvalsOf<Vec<ApprovalFlag>>([who.toString(), at]).pipe(
map((flags: Vec<ApprovalFlag>): boolean[] => approvalFlagsToBools(flags))
);
}
/**
* @name approvalsOfAt
@@ -26,9 +32,9 @@ import { drr } from '../util/drr';
* ```
*/
export function approvalsOfAt (api: ApiInterfaceRx): (who: AccountId, at: SetIndex) => Observable<boolean[]> {
return (who: AccountId | string, at: SetIndex | BN | number): Observable<boolean[]> =>
api.query.elections.approvalsOf<Vec<ApprovalFlag>>([who.toString(), at]).pipe(
map((flags: Vec<ApprovalFlag>): boolean[] => approvalFlagsToBools(flags)),
drr()
);
return memo((who: AccountId | string, at: SetIndex | BN | number): Observable<boolean[]> =>
api.query.elections
? queryElections(api, who, at)
: of([])
);
}
+75 -38
View File
@@ -2,30 +2,83 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, BlockNumber, SetIndex, VoteIndex } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import { AccountId, Balance, BlockNumber, SetIndex, VoteIndex } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { Observable } from 'rxjs';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec, u32 } from '@polkadot/types';
import { createType, Vec, u32 } from '@polkadot/types';
import { DerivedElectionsInfo } from '../types';
import { drr } from '../util/drr';
import { memo } from '../util';
type Result = [Vec<[AccountId, BlockNumber] & Codec>, Vec<AccountId>, u32, u32, SetIndex, BlockNumber, VoteIndex, SetIndex];
type ResultElectionsInner = [u32, u32, Vec<ITuple<[AccountId, BlockNumber]>>, SetIndex, BlockNumber, VoteIndex, SetIndex];
type ResultElections = [Vec<AccountId>, ResultElectionsInner];
function query (api: ApiInterfaceRx): Observable<Result> {
return api.queryMulti<Result>([
api.query.elections.members,
api.query.elections.candidates,
api.query.elections.candidateCount,
api.query.elections.desiredSeats,
api.query.elections.nextVoterSet,
api.query.elections.termDuration,
api.query.elections.voteCount,
api.query.elections.voterCount
]);
function deriveElections (api: ApiInterfaceRx, [candidates, [candidateCount, desiredSeats, members, nextVoterSet, termDuration, voteCount, voterCount]]: ResultElections): DerivedElectionsInfo {
return {
candidates,
candidateCount,
desiredSeats,
nextVoterSet,
members: members.map(([accountId]): [AccountId, Balance] => [accountId, createType(api.registry, 'Balance')]),
runnersUp: [],
termDuration,
voteCount,
voterCount
};
}
function queryElections (api: ApiInterfaceRx): Observable<DerivedElectionsInfo> {
// NOTE We have an issue where candidates can return `null` for an empty array
return combineLatest([
api.query.elections.candidates<Vec<AccountId>>(),
api.queryMulti<ResultElectionsInner>([
api.query.elections.candidateCount,
api.query.elections.desiredSeats,
api.query.elections.members,
api.query.elections.nextVoterSet,
api.query.elections.termDuration,
api.query.elections.voteCount,
api.query.elections.voterCount
])
]).pipe(map((result): DerivedElectionsInfo => deriveElections(api, result)));
}
function derivePhragmen (api: ApiInterfaceRx, candidates: AccountId[], members: [AccountId, Balance][], runnersUp: [AccountId, Balance][], candidacyBond: Balance, desiredSeats: u32, termDuration: BlockNumber, votingBond: Balance): DerivedElectionsInfo {
return {
candidates,
candidateCount: createType(api.registry, 'u32', candidates.length),
candidacyBond,
desiredSeats,
members,
// place in most-likely-to-be-in order
runnersUp: runnersUp.reverse(),
termDuration,
votingBond
};
}
function queryPhragmen (api: ApiInterfaceRx): Observable<DerivedElectionsInfo> {
// NOTE We have an issue where candidates can return `null` for an empty array, hence
// we are not using multi queries here, so empty array is empty (instead of space-filled)
return combineLatest([
api.query.electionsPhragmen.candidates<Vec<AccountId>>(),
api.query.electionsPhragmen.members<Vec<ITuple<[AccountId, Balance]>>>(),
api.query.electionsPhragmen.runnersUp<Vec<ITuple<[AccountId, Balance]>>>()
]).pipe(
map(([candidates, members, runnersUp]): DerivedElectionsInfo => derivePhragmen(
api,
candidates,
members,
runnersUp,
api.consts.electionsPhragmen.candidacyBond as Balance,
api.consts.electionsPhragmen.desiredMembers as u32,
api.consts.electionsPhragmen.termDuration as BlockNumber,
api.consts.electionsPhragmen.votingBond as Balance
))
);
}
/**
@@ -42,25 +95,9 @@ function query (api: ApiInterfaceRx): Observable<Result> {
* ```
*/
export function info (api: ApiInterfaceRx): () => Observable<DerivedElectionsInfo> {
return (): Observable<DerivedElectionsInfo> => {
return query(api).pipe(
map(([members, candidates, candidateCount, desiredSeats, nextVoterSet, termDuration, voteCount, voterCount]): DerivedElectionsInfo => ({
members: members.reduce(
(record: Record<string, BlockNumber>, [accountId, blockNumber]): Record<string, BlockNumber> => {
record[accountId.toString()] = blockNumber;
return record;
},
{}
),
candidates,
candidateCount,
desiredSeats,
nextVoterSet,
termDuration,
voteCount,
voterCount
})),
drr()
);
};
return memo((): Observable<DerivedElectionsInfo> =>
api.query.electionsPhragmen
? queryPhragmen(api)
: queryElections(api)
);
}
@@ -4,13 +4,41 @@
import { AccountId, SetIndex } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Vec, Option, createType } from '@polkadot/types';
import { Vec, Option, createType, u32 } from '@polkadot/types';
import { DerivedVoterPositions } from '../types';
import BN from 'bn.js';
import { of, combineLatest, Observable } from 'rxjs';
import { of, Observable } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { drr } from '../util/drr';
import { memo } from '../util';
function queryElections (api: ApiInterfaceRx): Observable<DerivedVoterPositions> {
return api.query.elections.nextVoterSet<SetIndex>().pipe(
switchMap((nextVoterSet: SetIndex): Observable<Vec<Option<AccountId>>[]> =>
api.query.elections.voters.multi<Vec<Option<AccountId>>>([...Array(+nextVoterSet + 1).keys()].map((_, i): [number] => [i]))
),
map((voters: Vec<Option<AccountId>>[]): DerivedVoterPositions => {
return voters.reduce((result: DerivedVoterPositions, vec, setIndex): DerivedVoterPositions => {
vec.forEach((e, index): void => {
// re-create the index based on position 0 is [0][0] and likewise
// 64 (0..63 in first) is [1][0] (the first index value in set 2)
const accountId: AccountId | null = e.unwrapOr(null);
if (accountId) {
result[accountId.toString()] = {
globalIndex: (api.consts.elections.voterSetSize as u32).muln(setIndex).addn(index),
index: new BN(index),
setIndex: createType(api.registry, 'SetIndex', setIndex)
};
}
});
return result;
}, {});
})
);
}
/**
* @name voterPositions
@@ -26,32 +54,9 @@ import { drr } from '../util/drr';
* ```
*/
export function voterPositions (api: ApiInterfaceRx): () => Observable<DerivedVoterPositions> {
return (): Observable<DerivedVoterPositions> =>
api.query.elections.nextVoterSet<SetIndex>().pipe(
switchMap((nextVoterSet: SetIndex): Observable<[BN, Vec<Option<AccountId>>[]]> => combineLatest(
of(api.consts.elections.voterSetSize) as any as Observable<BN>,
api.query.elections.voters.multi([...Array(+nextVoterSet + 1).keys()].map((_, i): [number] => [i])) as any as Observable<Vec<Option<AccountId>>[]>
)),
map((result: [BN, Vec<Option<AccountId>>[]]): DerivedVoterPositions => {
const [setSize, voters] = result;
return voters.reduce((result: DerivedVoterPositions, vec, setIndex): DerivedVoterPositions => {
vec.forEach((e, index): void => {
// re-create the index based on position 0 is [0][0] and likewise
// 64 (0..63 in first) is [1][0] (the first index value in set 2)
const accountId: AccountId | null = e.unwrapOr(null);
if (accountId) {
result[accountId.toString()] = {
globalIndex: setSize.muln(setIndex).addn(index),
index: new BN(index),
setIndex: createType('SetIndex', setIndex)
};
}
});
return result;
}, {});
}),
drr()
);
return memo((): Observable<DerivedVoterPositions> =>
api.query.elections
? queryElections(api)
: of({})
);
}
+21 -17
View File
@@ -6,13 +6,25 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId } from '@polkadot/types/interfaces';
import { DerivedVoterPositions } from '../types';
import { Observable } from 'rxjs';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { createType, Vec } from '@polkadot/types';
import { drr } from '../util/drr';
import { voterPositions } from './voterPositions';
import { memo } from '../util';
function queryElections (api: ApiInterfaceRx): Observable<AccountId[]> {
return api.derive.elections.voterPositions().pipe(
map((voterPositions: DerivedVoterPositions): Vec<AccountId> =>
createType(
api.registry,
'Vec<AccountId>',
Object.entries(voterPositions)
.sort((a, b): number => a[1].globalIndex.cmp(b[1].globalIndex))
.map(([accountId]): AccountId => createType(api.registry, 'AccountId', accountId))
)
)
);
}
/**
* @name voters
* @returns An array of all current voters from all sets.
@@ -25,18 +37,10 @@ import { voterPositions } from './voterPositions';
* });
* ```
*/
export function voters (api: ApiInterfaceRx): () => Observable<Vec<AccountId>> {
return (): Observable<Vec<AccountId>> =>
voterPositions(api)().pipe(
map(
(voterPositions: DerivedVoterPositions): Vec<AccountId> =>
createType(
'Vec<AccountId>',
Object.entries(voterPositions)
.sort((a, b): 0 | 1 | -1 => a[1].globalIndex.cmp(b[1].globalIndex))
.map(([accountId]): AccountId => createType('AccountId', accountId))
)
),
drr()
);
export function voters (api: ApiInterfaceRx): () => Observable<AccountId[]> {
return memo((): Observable<AccountId[]> =>
api.query.elections
? queryElections(api)
: of([])
);
}
@@ -3,36 +3,39 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, SessionIndex } from '@polkadot/types/interfaces';
import { DerivedHeartbeats } from '../types';
import { of, Observable } from 'rxjs';
import { of, Observable, combineLatest } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Bytes, Vec } from '@polkadot/types';
import { Bytes, Option, u32 } from '@polkadot/types';
import { drr } from '../util/drr';
import { memo } from '../util';
/**
* @description Return a boolean array indicating whether the passed accounts had received heartbeats in the current session
*/
export function receivedHeartbeats (api: ApiInterfaceRx): (addresses: (AccountId | string)[]) => Observable<boolean[]> {
return (addresses: (AccountId | string)[]): Observable<boolean[]> => {
return api.query.imOnline && api.query.imOnline.receivedHeartbeats
? api.queryMulti<[SessionIndex, Vec<AccountId>]>([
api.query.session.currentIndex,
api.query.imOnline.keys
]).pipe(
switchMap(([currentIndex, keys]): Observable<Bytes[]> =>
api.query.imOnline.receivedHeartbeats.multi(
addresses.map((address): [SessionIndex, number] =>
[currentIndex, keys.indexOf(address)]
)
)
export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable<DerivedHeartbeats> {
return memo((): Observable<DerivedHeartbeats> =>
api.query.imOnline?.receivedHeartbeats && api.query.imOnline.authoredBlocks
? api.derive.staking.overview().pipe(
switchMap(({ currentIndex, validators }): Observable<[AccountId[], Option<Bytes>[], u32[]]> =>
combineLatest([
of(validators),
api.query.imOnline.receivedHeartbeats.multi<Option<Bytes>>(validators.map((_address, index): [SessionIndex, number] => [currentIndex, index])),
api.query.imOnline.authoredBlocks.multi<u32>(validators.map((address): [SessionIndex, AccountId] => [currentIndex, address]))
])
),
map((heartbeats): boolean[] =>
heartbeats.map((heartbeat): boolean => !heartbeat.isEmpty)
),
drr()
map(([validators, heartbeats, numBlocks]): DerivedHeartbeats =>
validators.reduce((result: DerivedHeartbeats, validator, index): DerivedHeartbeats => ({
...result,
[validator.toString()]: {
blockCount: numBlocks[index],
hasMessage: !heartbeats[index].isEmpty,
isOnline: !heartbeats[index].isEmpty || numBlocks[index].gtn(0)
}
}), {})
)
)
: of([...new Array(addresses.length).keys()].map((): boolean => false));
};
: of({}));
}
+6 -2
View File
@@ -5,6 +5,7 @@
import { Observable, from } from 'rxjs';
import ApiRx from '@polkadot/api/rx/Api';
import MockProvider from '@polkadot/rpc-provider/mock';
import { TypeRegistry } from '@polkadot/types';
import { ExactDerive } from '.';
@@ -26,8 +27,10 @@ const testFunction = (api: ApiRx): any => {
};
describe('derive', (): void => {
const registry = new TypeRegistry();
describe('builtin', (): void => {
const api = new ApiRx({ provider: new MockProvider() });
const api = new ApiRx({ provider: new MockProvider(registry), registry });
beforeAll((done): void => {
api.isReady.subscribe((): void => done());
@@ -77,7 +80,8 @@ describe('derive', (): void => {
test: (): any => (): Observable<any> => from([1, 2, 3])
}
},
provider: new MockProvider()
provider: new MockProvider(registry),
registry
});
beforeAll((done): void => {
+9 -9
View File
@@ -2,18 +2,18 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import BN from 'bn.js';
import { BlockNumber } from '@polkadot/types/interfaces';
import { DerivedSessionInfo } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util/drr';
import { info } from './info';
import { memo } from '../util';
export function eraLength (api: ApiInterfaceRx): () => Observable<BN> {
return (): Observable<BN> =>
info(api)().pipe(
map(({ eraLength }): BN => eraLength),
drr()
);
export function eraLength (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return memo((): Observable<BlockNumber> =>
api.derive.session.info().pipe(
map(({ eraLength }: DerivedSessionInfo): BlockNumber => eraLength)
));
}
@@ -2,18 +2,18 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import BN from 'bn.js';
import { BlockNumber } from '@polkadot/types/interfaces';
import { DerivedSessionInfo } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util/drr';
import { info } from './info';
import { memo } from '../util';
export function eraProgress (api: ApiInterfaceRx): () => Observable<BN> {
return (): Observable<BN> =>
info(api)().pipe(
map(({ eraProgress }): BN => eraProgress),
drr()
);
export function eraProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return memo((): Observable<BlockNumber> =>
api.derive.session.info().pipe(
map(({ eraProgress }: DerivedSessionInfo): BlockNumber => eraProgress)
));
}
+1
View File
@@ -4,5 +4,6 @@
export * from './eraLength';
export * from './eraProgress';
export * from './indexes';
export * from './info';
export * from './sessionProgress';
@@ -0,0 +1,31 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { EraIndex, SessionIndex } from '@polkadot/types/interfaces';
import { DeriveSessionIndexes } from '../types';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { createType, u32 as U32 } from '@polkadot/types';
import { memo } from '../util';
export function indexes (api: ApiInterfaceRx): () => Observable<DeriveSessionIndexes> {
return memo((): Observable<DeriveSessionIndexes> =>
(
// Some chains (eg. very limited node-template), does not have session
api.query.session && api.query.staking
? api.queryMulti<[SessionIndex, EraIndex, U32]>([
api.query.session.currentIndex,
api.query.staking.currentEra,
api.query.staking.validatorCount
])
: of([createType(api.registry, 'SessionIndex', 1), createType(api.registry, 'EraIndex', 1), createType(api.registry, 'u32')])
).pipe(
map(([currentIndex, currentEra, validatorCount]): DeriveSessionIndexes => ({
currentIndex, currentEra, validatorCount
}))
));
}
+62 -73
View File
@@ -2,28 +2,26 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { BlockNumber, EraIndex, SessionIndex } from '@polkadot/types/interfaces';
import { DerivedSessionInfo } from '../types';
import { BlockNumber, SessionIndex } from '@polkadot/types/interfaces';
import { DerivedSessionInfo, DeriveSessionIndexes } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, u64, createType } from '@polkadot/types';
import { drr } from '../util/drr';
import { bestNumber } from '../chain';
import { memo } from '../util';
type Result94Session = [SessionIndex, Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
type Result94 = [BlockNumber, Result94Session];
type ResultV1Session = [Option<BlockNumber>, BlockNumber, BlockNumber, SessionIndex];
type ResultV1 = [BlockNumber, DeriveSessionIndexes, ResultV1Session];
type ResultIndex = [SessionIndex, EraIndex];
type ResultSlots = [u64, u64, u64];
type ResultType = [boolean, boolean, u64, SessionIndex];
type Result = [ResultType, ResultSlots, ResultIndex];
type ResultSlots = [u64, u64, u64, SessionIndex];
type ResultType = [boolean, u64, SessionIndex];
type Result = [ResultType, DeriveSessionIndexes, ResultSlots];
// internal helper to just split the logic - take all inputs, do the calculations and combine
function createDerived94 ([bestNumber, [currentIndex, _lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: Result94): DerivedSessionInfo {
const lastLengthChange = (_lastLengthChange && _lastLengthChange.unwrapOr(null)) || createType('BlockNumber');
function createDerivedV1 (api: ApiInterfaceRx, [bestNumber, { currentIndex, validatorCount }, [_lastLengthChange, sessionLength, lastEraLengthChange, sessionsPerEra]]: ResultV1): DerivedSessionInfo {
const lastLengthChange = _lastLengthChange?.unwrapOr(null) || createType(api.registry, 'BlockNumber');
const sessionProgress = bestNumber
.sub(lastLengthChange)
.add(sessionLength)
@@ -36,89 +34,80 @@ function createDerived94 ([bestNumber, [currentIndex, _lastLengthChange, session
.add(sessionProgress);
return {
currentEra: createType('EraIndex', currentEra),
currentEra: createType(api.registry, 'EraIndex', currentEra),
currentIndex,
eraLength: createType('BlockNumber', sessionLength.mul(sessionsPerEra)),
eraProgress: createType('BlockNumber', eraProgress),
eraLength: createType(api.registry, 'BlockNumber', sessionLength.mul(sessionsPerEra)),
eraProgress: createType(api.registry, 'BlockNumber', eraProgress),
isEpoch: false,
lastEraLengthChange,
lastLengthChange,
sessionLength,
sessionsPerEra,
sessionProgress: createType('BlockNumber', sessionProgress)
sessionProgress: createType(api.registry, 'BlockNumber', sessionProgress),
validatorCount
};
}
function createDerivedLatest ([[hasBabe, isGenesisSlot, epochDuration, sessionsPerEra], [currentSlot, epochIndex, epochOrGenesisStartSlot], [currentIndex, currentEra]]: Result): DerivedSessionInfo {
const epochStartSlot = isGenesisSlot
? epochIndex
.mul(epochDuration)
.add(epochOrGenesisStartSlot)
: epochOrGenesisStartSlot;
function createDerivedLatest (api: ApiInterfaceRx, [[hasBabe, epochDuration, sessionsPerEra], { currentIndex, currentEra, validatorCount }, [currentSlot, epochIndex, epochOrGenesisStartSlot, currentEraStartSessionIndex]]: Result): DerivedSessionInfo {
const epochStartSlot = epochIndex.mul(epochDuration).add(epochOrGenesisStartSlot);
const sessionProgress = currentSlot.sub(epochStartSlot);
const eraProgress = epochIndex
.mod(sessionsPerEra)
.mul(epochDuration)
.add(sessionProgress);
const eraProgress = currentIndex.sub(currentEraStartSessionIndex).mul(epochDuration).add(sessionProgress);
return {
currentEra,
currentIndex,
eraLength: createType('BlockNumber', sessionsPerEra.mul(epochDuration)),
eraProgress: createType('BlockNumber', eraProgress),
eraLength: createType(api.registry, 'BlockNumber', sessionsPerEra.mul(epochDuration)),
eraProgress: createType(api.registry, 'BlockNumber', eraProgress),
isEpoch: hasBabe,
lastEraLengthChange: createType('BlockNumber'),
lastLengthChange: createType('BlockNumber', epochStartSlot),
sessionLength: epochDuration,
sessionsPerEra,
sessionProgress: createType('BlockNumber', sessionProgress)
sessionProgress: createType(api.registry, 'BlockNumber', sessionProgress),
validatorCount
};
}
function info94 (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
function infoV1 (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return combineLatest([
bestNumber(api)(),
api.queryMulti<Result94Session>([
api.query.session.currentIndex,
api.derive.chain.bestNumber(),
api.derive.session.indexes(),
api.queryMulti<ResultV1Session>([
api.query.session.lastLengthChange,
api.query.session.sessionLength,
api.query.staking.lastEraLengthChange,
api.query.staking.sessionsPerEra
])
]).pipe(
map(createDerived94),
drr()
map((result): DerivedSessionInfo => createDerivedV1(api, result))
);
}
function infoLatest (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
const hasBabe = !!api.consts.babe;
return combineLatest([
of([
hasBabe,
hasBabe && !!api.query.babe.genesisSlot,
hasBabe
? api.consts.babe.epochDuration as u64
: createType('u64', 1),
api.consts.staking.sessionsPerEra as SessionIndex
] as ResultType),
hasBabe
? api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot
? api.query.babe.genesisSlot
: api.query.babe.epochStartSlot
function infoLatestAura (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return api.derive.session.indexes().pipe(
map((indexes): DerivedSessionInfo =>
createDerivedLatest(api, [
[false, createType(api.registry, 'u64', 1), api.consts.staking?.sessionsPerEra || createType(api.registry, 'SessionIndex', 1)],
indexes,
[createType(api.registry, 'u64', 1), createType(api.registry, 'u64', 1), createType(api.registry, 'u64', 1), createType(api.registry, 'SessionIndex', 1)]
])
: of([createType('u64', 1), createType('u64', 1), createType('u64', 1)] as ResultSlots),
api.queryMulti<ResultIndex>([
api.query.session.currentIndex,
api.query.staking.currentEra
)
);
}
function infoLatestBabe (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
return combineLatest([
api.derive.session.indexes(),
api.queryMulti<ResultSlots>([
api.query.babe.currentSlot,
api.query.babe.epochIndex,
api.query.babe.genesisSlot,
api.query.staking.currentEraStartSessionIndex
])
]).pipe(
map(createDerivedLatest),
drr()
map(([indexes, slots]: [DeriveSessionIndexes, ResultSlots]): DerivedSessionInfo =>
createDerivedLatest(api, [
[true, api.consts.babe.epochDuration, api.consts.staking.sessionsPerEra],
indexes,
slots
])
)
);
}
@@ -126,12 +115,12 @@ function infoLatest (api: ApiInterfaceRx): Observable<DerivedSessionInfo> {
* @description Retrieves all the session and era info and calculates specific values on it as the length of the session and eras
*/
export function info (api: ApiInterfaceRx): () => Observable<DerivedSessionInfo> {
return (): Observable<DerivedSessionInfo> => {
// With substrate `spec_version 94`, the era and session has been explicitly exposed as `parameter_types`.
// pre-94 we had more info and needed to calculate (handle old/Alex first)
// https://github.com/paritytech/substrate/commit/dbf322620948935d2bbae214504e6c668c3073ed#diff-c29f42d6b931fa93ba038dbbbfec3055
return api.query.session.lastLengthChange
? info94(api) // 1.x
: infoLatest(api); // 2.x
};
const query = api.consts.timestamp || api.consts.babe || api.consts.aura
? api.consts.babe
? infoLatestBabe // 2.x with Babe
: infoLatestAura // 2.x with Aura (not all info there)
: infoV1;
return memo((): Observable<DerivedSessionInfo> =>
query(api));
}
@@ -2,18 +2,18 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import BN from 'bn.js';
import { BlockNumber } from '@polkadot/types/interfaces';
import { DerivedSessionInfo } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { drr } from '../util/drr';
import { info } from './info';
import { memo } from '../util';
export function sessionProgress (api: ApiInterfaceRx): () => Observable<BN> {
return (): Observable<BN> =>
info(api)().pipe(
map(({ sessionProgress }): BN => sessionProgress),
drr()
);
export function sessionProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return memo((): Observable<BlockNumber> =>
api.derive.session.info().pipe(
map(({ sessionProgress }: DerivedSessionInfo): BlockNumber => sessionProgress)
));
}
+20 -19
View File
@@ -2,31 +2,32 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, ValidatorPrefs } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { Observable, combineLatest, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option } from '@polkadot/types';
import { Option, Vec } from '@polkadot/types';
import { drr } from '../util/drr';
import { memo } from '../util';
type DeriveControllers = [AccountId[], Option<AccountId>[]];
/**
* @description From the list of stash accounts, retrieve the list of controllers
*/
export function controllers (api: ApiInterfaceRx): () => Observable<[AccountId[], Option<AccountId>[]]> {
return (): Observable<[AccountId[], Option<AccountId>[]]> =>
api.query.staking
.validators<[AccountId[]] & Codec>()
.pipe(
switchMap(([stashIds]): Observable<[AccountId[], Option<AccountId>[]]> =>
combineLatest([
of(stashIds),
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
api.query.staking.bonded.multi(stashIds) as Observable<Option<AccountId>[]>
])
),
drr()
);
export function controllers (api: ApiInterfaceRx): () => Observable<DeriveControllers> {
return memo((): Observable<[AccountId[], Option<AccountId>[]]> =>
api.query.staking.validators<ITuple<[Vec<AccountId>, Vec<ValidatorPrefs>]>>().pipe(
switchMap(([stashIds]): Observable<DeriveControllers> =>
combineLatest([
of(stashIds),
// for V2, don't return all the controllers, we call bonded at a later point
api.consts.session
? of([])
: api.query.staking.bonded.multi<Option<AccountId>>(stashIds)
])
)
));
}
@@ -0,0 +1,30 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId } from '@polkadot/types/interfaces';
import { DerivedStaking, DerivedStakingElected } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { memo } from '../util';
export function electedInfo (api: ApiInterfaceRx): () => Observable<DerivedStakingElected> {
return memo((): Observable<DerivedStakingElected> =>
api.derive.staking.validators().pipe(
switchMap(({ currentElected }): Observable<[AccountId[], DerivedStaking[]]> =>
combineLatest([
of(currentElected),
combineLatest(currentElected.map((accountId): Observable<DerivedStaking> =>
api.derive.staking.info(accountId)
))
])
),
map(([currentElected, info]): DerivedStakingElected => ({
currentElected, info
}))
)
);
}
+3
View File
@@ -3,5 +3,8 @@
// of the Apache-2.0 license. See the LICENSE file for details.
export * from './controllers';
export * from './electedInfo';
export * from './info';
export * from './overview';
export * from './recentlyOffline';
export * from './validators';
+127 -90
View File
@@ -2,13 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Balance, BlockNumber } from '@polkadot/types/interfaces/runtime';
import { Keys } from '@polkadot/types/interfaces/session';
import { Exposure, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces/staking';
import { Codec } from '@polkadot/types/types';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedStaking, DerivedUnlocking } from '../types';
import { AccountId, Balance, BlockNumber, Exposure, Keys, Nominations, RewardDestination, StakingLedger, UnlockChunk, ValidatorPrefs } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DerivedRecentlyOffline, DerivedSessionInfo, DerivedStaking, DerivedUnlocking } from '../types';
import BN from 'bn.js';
import { combineLatest, Observable, of } from 'rxjs';
@@ -17,14 +14,23 @@ import { createType, Option, Vec } from '@polkadot/types';
import { isUndefined } from '@polkadot/util';
import { bestNumber } from '../chain/bestNumber';
import { eraLength } from '../session/eraLength';
import { recentlyOffline } from './recentlyOffline';
import { drr } from '../util/drr';
import { memo } from '../util';
type MultiResult = [Option<Keys>, [
Option<AccountId> | Vec<[AccountId, Keys] & Codec>, Option<StakingLedger>, [AccountId[]], RewardDestination, Exposure, [ValidatorPrefs]
]];
interface ParseInput {
accountId: AccountId;
controllerId: AccountId;
recentlyOffline?: DerivedRecentlyOffline;
nominators: AccountId[];
rewardDestination: RewardDestination;
queuedKeys?: [AccountId, Keys][];
sessionInfo: DerivedSessionInfo;
stakers: Exposure;
stakingLedger: Option<StakingLedger>;
stashId: AccountId;
validatorPrefs: ValidatorPrefs;
nextKeys?: Option<Keys>;
nextKeyFor?: Option<AccountId>;
}
// groups the supplied chunks by era, i.e. { [era]: BN(total of values) }
function groupByEra (list: UnlockChunk[]): Record<string, BN> {
@@ -39,52 +45,56 @@ function groupByEra (list: UnlockChunk[]): Record<string, BN> {
}, {});
}
// calculate the remining blocks in a specific unlock era
function remainingBlocks (era: BN, eraLength: BN, bestNumber: BlockNumber): BlockNumber {
const remaining = eraLength.mul(era).sub(bestNumber);
// calculate the remaining blocks in a specific unlock era
function remainingBlocks (api: ApiInterfaceRx, era: BN, sessionInfo: DerivedSessionInfo): BlockNumber {
const remaining = era.sub(sessionInfo.currentEra);
return createType('BlockNumber', remaining.lten(0)
? new BN(0)
: remaining
// on the Rust side the current-era >= era-for-unlock (removal done on >)
return createType(api.registry, 'BlockNumber', remaining.gtn(0)
? remaining
.subn(1)
.mul(sessionInfo.eraLength)
.add(sessionInfo.eraLength.sub(sessionInfo.eraProgress))
: 0
);
}
function calculateUnlocking (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): DerivedUnlocking[] | undefined {
function calculateUnlocking (api: ApiInterfaceRx, stakingLedger: StakingLedger | undefined, sessionInfo: DerivedSessionInfo): DerivedUnlocking[] | undefined {
if (isUndefined(stakingLedger)) {
return undefined;
}
const unlockingChunks = stakingLedger.unlocking.filter(({ era }): boolean =>
remainingBlocks(era.unwrap(), eraLength, bestNumber).gtn(0)
remainingBlocks(api, era.unwrap(), sessionInfo).gtn(0)
);
if (!unlockingChunks.length) {
return undefined;
}
// group the Unlockchunks that have the same era and sum their values
// group the unlock chunks that have the same era and sum their values
const groupedResult = groupByEra(unlockingChunks);
const results = Object.entries(groupedResult).map(([eraString, value]): DerivedUnlocking => ({
value: createType('Balance', value),
remainingBlocks: remainingBlocks(createType('BlockNumber', eraString), eraLength, bestNumber)
value: createType(api.registry, 'Balance', value),
remainingBlocks: remainingBlocks(api, new BN(eraString), sessionInfo)
}));
return results.length ? results : undefined;
}
function redeemableSum (stakingLedger: StakingLedger | undefined, eraLength: BN, bestNumber: BlockNumber): Balance {
function redeemableSum (api: ApiInterfaceRx, stakingLedger: StakingLedger | undefined, sessionInfo: DerivedSessionInfo): Balance {
if (isUndefined(stakingLedger)) {
return createType('Balance');
return createType(api.registry, 'Balance');
}
return createType('Balance', stakingLedger.unlocking.reduce((total, { era, value }): BN => {
return remainingBlocks(era.unwrap(), eraLength, bestNumber).eqn(0)
return createType(api.registry, 'Balance', stakingLedger.unlocking.reduce((total, { era, value }): BN => {
return remainingBlocks(api, era.unwrap(), sessionInfo).eqn(0)
? total.add(value.unwrap())
: total;
}, new BN(0)));
}
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | Vec<[AccountId, Keys] & Codec>, nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; nextSessionId?: AccountId; sessionIds: AccountId[]; sessionId?: AccountId } {
function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | [AccountId, Keys][], nextKeys: Option<Keys>): { nextSessionIds: AccountId[]; sessionIds: AccountId[] } {
// for 2.x we have a Vec<(ValidatorId,Keys)> of the keys
if (Array.isArray(queuedKeys)) {
const sessionIds = (queuedKeys.find(([currentId]): boolean =>
@@ -93,9 +103,7 @@ function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | V
const nextSessionIds = nextKeys.unwrapOr([] as AccountId[]);
return {
nextSessionId: nextSessionIds[0],
nextSessionIds,
sessionId: sessionIds[0],
sessionIds
};
}
@@ -106,85 +114,114 @@ function unwrapSessionIds (stashId: AccountId, queuedKeys: Option<AccountId> | V
: [];
return {
nextSessionId: nextSessionIds[0],
nextSessionIds,
sessionId: nextSessionIds[0],
sessionIds: nextSessionIds
};
}
function retrieveMulti (api: ApiInterfaceRx, stashId: AccountId, controllerId: AccountId): Observable<MultiResult> {
function parseResult (api: ApiInterfaceRx, { accountId, controllerId, stashId, sessionInfo, recentlyOffline = {}, nextKeyFor, queuedKeys, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs, nextKeys }: ParseInput): DerivedStaking {
const _stakingLedger = stakingLedger.unwrapOr(undefined);
const _nextKeyFor = nextKeyFor || createType(api.registry, 'Option<AccountId>', null);
const _nextKeys = nextKeys || createType(api.registry, 'Option<Keys>', null);
return {
accountId,
controllerId,
nominators,
offline: recentlyOffline[stashId.toString()],
redeemable: redeemableSum(api, _stakingLedger, sessionInfo),
rewardDestination,
stakers,
stakingLedger: _stakingLedger,
stashId,
unlocking: calculateUnlocking(api, _stakingLedger, sessionInfo),
validatorPrefs,
...unwrapSessionIds(stashId, queuedKeys || _nextKeyFor, _nextKeys)
};
}
type MultiResultV1 = [Option<AccountId>, Option<StakingLedger>, [Vec<AccountId>], RewardDestination, Exposure, ITuple<[ValidatorPrefs]>];
function retrieveInfoV1 (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
return combineLatest([
// TODO We really want this as part of the multi, however can only do that
// once we drop substrate 1.x support (nulti requires values for all)
api.query.session.nextKeys
? api.query.session.nextKeys<Option<Keys>>(api.consts.session.dedupKeyPrefix, stashId)
: of(createType('Option<Keys>', null)),
api.derive.session.info(),
api.derive.staking.recentlyOffline(),
api.queryMulti([
api.query.session.queuedKeys
? [api.query.session.queuedKeys]
: [api.query.session.nextKeyFor, controllerId],
[api.query.session.nextKeyFor, controllerId],
[api.query.staking.ledger, controllerId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId]
])
]) as Observable<MultiResult>;
]) as Observable<MultiResultV1>
]).pipe(map(([sessionInfo, recentlyOffline, [nextKeyFor, stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs]]]: [DerivedSessionInfo, DerivedRecentlyOffline, MultiResultV1]): DerivedStaking =>
parseResult(api, {
accountId, controllerId, stashId, sessionInfo, recentlyOffline, nextKeyFor, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs
})
));
}
function retrieveInfo (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
return combineLatest([
eraLength(api)(),
bestNumber(api)(),
recentlyOffline(api)(),
retrieveMulti(api, stashId, controllerId)
]).pipe(
map(([eraLength, bestNumber, recentlyOffline, [nextKeys, [queuedKeys, _stakingLedger, [nominators], rewardDestination, stakers, [validatorPrefs]]]]): DerivedStaking => {
const stakingLedger = _stakingLedger.unwrapOr(undefined);
type MultiResultV2 = [[Vec<AccountId>] | Option<ITuple<[Nominations]>>, RewardDestination, Exposure, [ValidatorPrefs], Option<Keys>, Option<StakingLedger>];
return {
accountId,
controllerId,
nominators,
offline: recentlyOffline[stashId.toString()],
redeemable: redeemableSum(stakingLedger, eraLength, bestNumber),
rewardDestination,
stakers,
stakingLedger,
stashId,
unlocking: calculateUnlocking(stakingLedger, eraLength, bestNumber),
validatorPrefs,
...unwrapSessionIds(stashId, queuedKeys, nextKeys)
};
})
);
function retrieveInfoV2 (api: ApiInterfaceRx, accountId: AccountId, stashId: AccountId, controllerId: AccountId): Observable<DerivedStaking> {
return combineLatest([
api.derive.session.info(),
api.query.session.queuedKeys<Vec<ITuple<[AccountId, Keys]>>>(),
api.queryMulti([
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId],
[api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]],
[api.query.staking.ledger, controllerId]
]) as Observable<MultiResultV2>
]).pipe(map(([sessionInfo, queuedKeys, [_nominators, rewardDestination, stakers, [validatorPrefs], nextKeys, stakingLedger]]: [DerivedSessionInfo, [AccountId, Keys][], MultiResultV2]): DerivedStaking => {
// if we have staking.storageVersion it indicates the new structure, unwrap as needed
// FIXME We really want to be pulling all the new (valuable) info along
const nominators: AccountId[] = api.query.staking.storageVersion
? (_nominators as Option<ITuple<[Nominations]>>).isSome
? (_nominators as Option<ITuple<[Nominations]>>).unwrap()[0].targets
: []
: (_nominators as [Vec<AccountId>])[0];
return parseResult(api, {
accountId, controllerId, stashId, sessionInfo, queuedKeys, stakingLedger, nominators, rewardDestination, stakers, validatorPrefs, nextKeys
});
}));
}
function retrieveV1 (api: ApiInterfaceRx, accountId: AccountId): Observable<DerivedStaking> {
// depending on where we come from, this may be a controller or stash
return combineLatest([
api.query.staking.bonded<Option<AccountId>>(accountId),
api.query.staking.ledger<Option<StakingLedger>>(accountId)
]).pipe(switchMap(([bonded, stakingLedger]): Observable<DerivedStaking> =>
stakingLedger.isSome
? retrieveInfoV1(api, accountId, stakingLedger.unwrap().stash, accountId)
: bonded.isSome
? retrieveInfoV1(api, accountId, accountId, bonded.unwrap())
: of({ accountId: accountId, nextSessionIds: [], sessionIds: [] })
));
}
function retrieveV2 (api: ApiInterfaceRx, stashId: AccountId): Observable<DerivedStaking> {
return api.query.staking
.bonded<Option<AccountId>>(stashId)
.pipe(switchMap((controllerId): Observable<DerivedStaking> =>
controllerId.isSome
? retrieveInfoV2(api, stashId, stashId, controllerId.unwrap())
: of({ accountId: stashId, nextSessionIds: [], sessionIds: [] })
));
}
/**
* @description From a stash, retrieve the controllerId and fill in all the relevant staking details
*/
export function info (api: ApiInterfaceRx): (_accountId: Uint8Array | string) => Observable<DerivedStaking> {
return (_accountId: Uint8Array | string): Observable<DerivedStaking> => {
const accountId = createType('AccountId', _accountId);
const query = api.consts.session
? retrieveV2
: retrieveV1;
return (
// NOTE For 2.x-only support, only the first path is required, therefore we
// can replace this with `.bonded<Option<AccountId>>(accountId)` - in 2.x
// the session.validators return the stashes (as expected)
api.queryMulti<[Option<AccountId>, Option<StakingLedger>]>([
[api.query.staking.bonded, accountId], // try to map to controller
[api.query.staking.ledger, accountId] // try to map to stash (1.x only)
])
).pipe(
switchMap(([controllerId, stakingLedger]): Observable<DerivedStaking> =>
controllerId.isSome
? retrieveInfo(api, accountId, accountId, controllerId.unwrap())
: stakingLedger.isSome
? retrieveInfo(api, accountId, stakingLedger.unwrap().stash, accountId)
: of({ accountId, nextSessionIds: [], sessionIds: [] })
),
drr()
);
};
return memo((accountId: Uint8Array | string): Observable<DerivedStaking> =>
query(api, createType(api.registry, 'AccountId', accountId)));
}
@@ -0,0 +1,64 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, Exposure, Keys, RewardDestination, ValidatorPrefs } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DerivedStakingStash } from '../types';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Option, Vec } from '@polkadot/types';
import { memo } from '../util';
// NOTE Unused ATM, preparing for V2-only
type Result = [Option<AccountId>, [Vec<AccountId>], RewardDestination, Exposure, ValidatorPrefs, Option<Keys>?];
type ResultV1 = [Option<AccountId>, ITuple<[Vec<AccountId>]>, RewardDestination, Exposure, ValidatorPrefs];
type ResultV2 = [Option<AccountId>, ITuple<[Vec<AccountId>]>, RewardDestination, Exposure, ValidatorPrefs, Option<Keys>];
function parse (stashId: AccountId, [_controllerId, [nominators], rewardDestination, stakers, validatorPrefs, _nextKeys]: Result): DerivedStakingStash {
return {
controllerId: _controllerId.unwrapOr(undefined),
nextKeys: _nextKeys?.unwrapOr(undefined),
nominators,
rewardDestination,
stakers,
stashId,
validatorPrefs
};
}
function retrieveV1 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
return api.queryMulti<ResultV1>([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId]
]);
}
function retrieveV2 (api: ApiInterfaceRx, stashId: AccountId): Observable<Result> {
return api.queryMulti<ResultV2>([
[api.query.staking.bonded, stashId],
[api.query.staking.nominators, stashId],
[api.query.staking.payee, stashId],
[api.query.staking.stakers, stashId],
[api.query.staking.validators, stashId],
[api.query.session.nextKeys, [api.consts.session.dedupKeyPrefix, stashId]]
]);
}
export function infoStash (api: ApiInterfaceRx): (stashId: AccountId) => Observable<DerivedStakingStash> {
const query = api.consts.session
? retrieveV2
: retrieveV1;
return memo((stashId: AccountId): Observable<DerivedStakingStash> =>
query(api, stashId).pipe(
map((result): DerivedStakingStash => parse(stashId, result))
));
}
@@ -0,0 +1,37 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { EraPoints } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DerivedStakingOverview } from '../types';
import { Observable, combineLatest, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { createType } from '@polkadot/types';
import { memo } from '../util';
/**
* @description Retrieve the staking overview, including elected and points earned
*/
export function overview (api: ApiInterfaceRx): () => Observable<DerivedStakingOverview> {
return memo((): Observable<DerivedStakingOverview> =>
combineLatest([
api.derive.session.indexes(),
api.derive.staking.validators()
]).pipe(
switchMap(([{ currentEra, currentIndex, validatorCount }, { currentElected, validators }]) =>
combineLatest([
of({ currentElected, currentEra, currentIndex, validators, validatorCount }),
// this will change on a per block basis, keep it innermost (and it needs eraIndex)
api.query.staking?.currentEraPointsEarned
? api.query.staking.currentEraPointsEarned<EraPoints>(currentEra)
: of(createType(api.registry, 'EraPoints'))
])
),
map(([{ currentElected, currentEra, currentIndex, validators, validatorCount }, eraPoints]): DerivedStakingOverview => ({
currentElected, currentEra, currentIndex, eraPoints, validators, validatorCount
}))
));
}
@@ -2,18 +2,18 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, BlockNumber } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import BN from 'bn.js';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { AccountId, BlockNumber } from '@polkadot/types/interfaces';
import { ITuple } from '@polkadot/types/types';
import { DerivedRecentlyOffline } from '../types';
import { drr } from '../util/drr';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Vec, u32 } from '@polkadot/types';
type OfflineResult = [AccountId, BlockNumber, BN][] & Codec;
import { memo } from '../util';
type OfflineResult = Vec<ITuple<[AccountId, BlockNumber, u32]>>;
function expandDerived (recentlyOffline: OfflineResult): DerivedRecentlyOffline {
return recentlyOffline.reduce((result: DerivedRecentlyOffline, [accountId, blockNumber, count]): DerivedRecentlyOffline => {
@@ -36,7 +36,7 @@ function expandDerived (recentlyOffline: OfflineResult): DerivedRecentlyOffline
* @description Retrieve a keyed record of accounts recently reported to be offline
*/
export function recentlyOffline (api: ApiInterfaceRx): () => Observable<DerivedRecentlyOffline> {
return (): Observable<DerivedRecentlyOffline> =>
return memo((): Observable<DerivedRecentlyOffline> =>
(
// TODO recentlyOffline has been dropped for 2.x and replaced, figure out the
// replacement as actually use and implement it
@@ -44,7 +44,6 @@ export function recentlyOffline (api: ApiInterfaceRx): () => Observable<DerivedR
? api.query.staking.recentlyOffline<OfflineResult>()
: of([] as unknown as OfflineResult)
).pipe(
map(expandDerived),
drr()
);
map(expandDerived)
));
}
@@ -0,0 +1,34 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { DeriveStakingValidators } from '../types';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Vec } from '@polkadot/types';
import { memo } from '../util';
/**
* @description Retrieve latest list of validators
*/
export function validators (api: ApiInterfaceRx): () => Observable<DeriveStakingValidators> {
return memo((): Observable<DeriveStakingValidators> =>
(
// Sadly the node-template is (for some obscure reason) not comprehensive, so while the derive works
// in all actual real-world deployed chains, it does create some confusion for limited template chains
api.query.session && api.query.staking
? api.queryMulti<[Vec<AccountId>, Vec<AccountId>]>([
api.query.session.validators,
api.query.staking.currentElected
])
: of([[], []] as [AccountId[], AccountId[]])
).pipe(
map(([validators, currentElected]): DeriveStakingValidators => ({
currentElected, validators
}))
));
}
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Header } from '@polkadot/types/interfaces';
import { AnyJsonObject, Constructor } from '@polkadot/types/types';
import { AnyJsonObject, Constructor, Registry } from '@polkadot/types/types';
import runtimeTypes from '@polkadot/types/interfaces/runtime/definitions';
import { Struct } from '@polkadot/types';
@@ -19,8 +19,8 @@ const _Header: Constructor<Header> = Struct.with(runtimeTypes.types.Header as an
export default class HeaderExtended extends _Header {
private _author?: AccountId;
public constructor (header?: Header, sessionValidators?: AccountId[]) {
super(header);
constructor (registry: Registry, header?: Header, sessionValidators?: AccountId[]) {
super(registry, header);
this._author = this.extractAuthor(sessionValidators);
}
@@ -3,7 +3,7 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { ReferendumIndex, ReferendumInfo } from '@polkadot/types/interfaces/democracy';
import { AnyJsonObject, Constructor } from '@polkadot/types/types';
import { AnyJsonObject, Constructor, Registry } from '@polkadot/types/types';
import BN from 'bn.js';
import democracyTypes from '@polkadot/types/interfaces/democracy/definitions';
@@ -20,12 +20,12 @@ const _ReferendumInfo: Constructor<ReferendumInfo> = Struct.with(democracyTypes.
export default class ReferendumInfoExtended extends _ReferendumInfo {
private _index: ReferendumIndex;
public constructor (value: ReferendumInfo | ReferendumInfoExtended, index?: BN | number) {
super(value);
constructor (registry: Registry, value: ReferendumInfo | ReferendumInfoExtended, index?: BN | number) {
super(registry, value);
this._index = value instanceof ReferendumInfoExtended
? value.index
: createType('ReferendumIndex', index);
: createType(registry, 'ReferendumIndex', index);
}
/**
+59 -19
View File
@@ -2,20 +2,31 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId, Balance, BlockNumber, EraIndex, Exposure, Index, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import { AccountId, AccountIndex, Balance, BalanceLock, BlockNumber, EraIndex, EraPoints, Exposure, Index, Keys, RewardDestination, SessionIndex, SetIndex, StakingLedger, ValidatorPrefs, Vote, VoteIndex } from '@polkadot/types/interfaces';
import BN from 'bn.js';
import { u32 } from '@polkadot/types';
export type AccountIndexes = Record<string, AccountIndex>;
export interface DeriveAccountInfo {
accountId?: AccountId;
accountIndex?: AccountIndex;
nickname?: string;
}
export interface DerivedBalances {
accountId: AccountId;
accountNonce: Index;
freeBalance: Balance;
isVesting: boolean;
lockedBalance: Balance;
lockedBreakdown: BalanceLock[];
availableBalance: Balance;
reservedBalance: Balance;
votingBalance: Balance;
vestedBalance: Balance;
vestingTotal: Balance;
}
export type DerivedBalancesMap = Record<string, DerivedBalances>;
@@ -34,14 +45,17 @@ export interface DerivedContractFees {
}
export interface DerivedElectionsInfo {
members: Record<string, BlockNumber>;
candidates: AccountId[];
candidateCount: u32;
candidacyBond?: Balance;
desiredSeats: u32;
nextVoterSet: SetIndex;
members: [AccountId, Balance][];
nextVoterSet?: SetIndex;
runnersUp: [AccountId, Balance][];
termDuration: BlockNumber;
voteCount: VoteIndex;
voterCount: SetIndex;
voteCount?: VoteIndex;
voterCount?: SetIndex;
votingBond?: Balance;
}
export interface DerivedFees {
@@ -52,6 +66,14 @@ export interface DerivedFees {
transferFee: Balance;
}
export interface DerivedHeartbeatAuthor {
blockCount: u32;
hasMessage: boolean;
isOnline: boolean;
}
export type DerivedHeartbeats = Record<string, DerivedHeartbeatAuthor>;
export interface RecentlyOffline {
blockNumber: BlockNumber;
count: BN;
@@ -65,14 +87,16 @@ export interface DerivedReferendumVote {
vote: Vote;
}
export interface DerivedSessionInfo {
export interface DeriveSessionIndexes {
currentEra: EraIndex;
currentIndex: SessionIndex;
validatorCount: u32;
}
export interface DerivedSessionInfo extends DeriveSessionIndexes {
eraLength: BlockNumber;
eraProgress: BlockNumber;
isEpoch: boolean;
lastEraLengthChange: BlockNumber;
lastLengthChange: BlockNumber;
sessionLength: BlockNumber;
sessionsPerEra: SessionIndex;
sessionProgress: BlockNumber;
@@ -82,6 +106,11 @@ export type DerivedStakingAccount = [AccountId, DerivedStakingOnlineStatus];
export type DerivedStakingAccounts = DerivedStakingAccount[];
export interface DerivedStakingElected {
currentElected: AccountId[];
info: DerivedStaking[];
}
export interface DerivedStakingOnlineStatus {
online?: {
isOnline: boolean;
@@ -93,25 +122,36 @@ export interface DerivedStakingOnlineStatus {
}[];
}
export interface DerivedStaking extends DerivedStakingOnlineStatus {
accountId: AccountId;
export interface DeriveStakingValidators {
currentElected: AccountId[];
validators: AccountId[];
}
export interface DerivedStakingStash {
controllerId?: AccountId;
// @deprecated Use nextSessionIds instead
nextSessionId?: AccountId;
nextSessionIds: AccountId[];
nominators?: AccountId[];
redeemable?: Balance;
rewardDestination?: RewardDestination;
// @deprecated Use sessionIds instead
sessionId?: AccountId;
sessionIds: AccountId[];
nextKeys?: Keys;
stakers?: Exposure;
stakingLedger?: StakingLedger;
stashId?: AccountId;
unlocking?: DerivedUnlocking[];
validatorPrefs?: ValidatorPrefs;
}
export interface DerivedStaking extends DerivedStakingOnlineStatus, DerivedStakingStash {
accountId: AccountId;
nextSessionIds: AccountId[];
redeemable?: Balance;
sessionIds: AccountId[];
stakingLedger?: StakingLedger;
unlocking?: DerivedUnlocking[];
}
export interface DerivedStakingOverview extends DeriveSessionIndexes {
currentElected: AccountId[];
eraPoints: EraPoints;
validators: AccountId[];
}
export type DerivedUnlocking = { remainingBlocks: BlockNumber; value: Balance };
export interface VoterPosition {
@@ -4,11 +4,13 @@
import { ApprovalFlag } from '@polkadot/types/interfaces';
import { createType } from '@polkadot/types';
import { createType, TypeRegistry } from '@polkadot/types';
import { approvalFlagsToBools } from './approvalFlagsToBools';
describe('approvalFlagsToBools', (): void => {
const registry = new TypeRegistry();
it('translates and empty array to empty', (): void => {
expect(
approvalFlagsToBools([] as ApprovalFlag[])
@@ -18,7 +20,7 @@ describe('approvalFlagsToBools', (): void => {
it('translates a single input', (): void => {
expect(
approvalFlagsToBools([
createType('ApprovalFlag', 0b1010)
createType(registry, 'ApprovalFlag', 0b1010)
])
).toEqual([false, true, false, true]);
});
@@ -26,8 +28,8 @@ describe('approvalFlagsToBools', (): void => {
it('translates multiple inputs', (): void => {
expect(
approvalFlagsToBools([
createType('ApprovalFlag', 0b0000),
createType('ApprovalFlag', 0b1100)
createType(registry, 'ApprovalFlag', 0b0000),
createType(registry, 'ApprovalFlag', 0b1100)
])
).toEqual([false, false, false, true, true]);
});
-30
View File
@@ -1,30 +0,0 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { catchError, distinctUntilChanged, publishReplay, refCount } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { logger } from '@polkadot/util';
type DrrResult = <T> (source$: Observable<T>) => Observable<T>;
const l = logger('drr');
/**
* Shorthand for distinctUntilChanged(), publishReplay(1) and refCount().
*
* @ignore
*/
export const drr = (): DrrResult => <T> (source$: Observable<T>): Observable<T> =>
source$.pipe(
catchError((error): Observable<never> => {
l.error(error);
throw error;
}),
distinctUntilChanged((a: any, b: any): boolean =>
JSON.stringify({ value: a }) === JSON.stringify({ value: b })
),
publishReplay(1),
refCount()
);
+1
View File
@@ -3,3 +3,4 @@
// of the Apache-2.0 license. See the LICENSE file for details.
export * from './approvalFlagsToBools';
export * from './memo';
+33
View File
@@ -0,0 +1,33 @@
// Copyright 2017-2019 @polkadot/api-derive authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.v
import createMemo from 'memoizee';
import { Observable, Observer } from 'rxjs';
import { drr } from '@polkadot/rpc-core/rxjs';
type ObsFn <T> = (...params: any[]) => Observable<T>;
// Normalize via JSON.stringify, allow e.g. AccountId -> ss58
// eslint-disable-next-line @typescript-eslint/unbound-method
const normalizer = JSON.stringify;
// Wraps a derive, doing 2 things to optimize calls -
// 1. creates a memo of the inner fn -> Observable, removing when unsubscribed
// 2. wraps the observable in a drr() (which includes an unsub delay)
export function memo <T> (inner: ObsFn<T>): ObsFn<T> {
const cached = createMemo(
(...params: any[]): Observable<T> =>
Observable.create((observer: Observer<T>): VoidCallback => {
const sub = inner(...params).subscribe(observer);
return (): void => {
cached.delete(...params);
sub.unsubscribe();
};
}).pipe(drr()),
{ normalizer }
);
return cached;
}
-1
View File
@@ -1 +0,0 @@
# @polkadot/api-metadata
@@ -1,3 +0,0 @@
# @polkadot/api-metadata/consts
A base interface to the parameter types
@@ -1,12 +0,0 @@
// Copyright 2017-2019 @polkadot/api-metadata authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Metadata } from '@polkadot/types';
import metadataRpc from '@polkadot/types/Metadata/static';
import fromMetadata from './fromMetadata';
export default fromMetadata(
new Metadata(metadataRpc)
);
-14
View File
@@ -1,14 +0,0 @@
// Copyright 2017-2019 @polkadot/api-metadata authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { Codec } from '@polkadot/types/types';
import { ModuleConstantMetadataLatest } from '@polkadot/types/interfaces';
export interface ConstantCodec extends Codec {
meta: ModuleConstantMetadataLatest;
}
export type ModuleConstants = Record<string, Codec>;
export type Constants = Record<string, ModuleConstants>;
@@ -1,3 +0,0 @@
# @polkadot/api-metadata/extrinsics
Base extrinsic definitions & codecs
@@ -1,15 +0,0 @@
// Copyright 2017-2019 @polkadot/api-metadata authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ModulesWithCalls } from '@polkadot/types/types';
import Metadata from '@polkadot/types/Metadata';
import metadataRpc from '@polkadot/types/Metadata/static';
import fromMetadata from './fromMetadata';
const staticMetadata: ModulesWithCalls = fromMetadata(
new Metadata(metadataRpc)
);
export default staticMetadata;
@@ -1,3 +0,0 @@
# @polkadot/api-metadata/storage
A base interface to the storage layer

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