Compare commits

..
211 Commits
Author SHA1 Message Date
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
Github Actions 27871135a0 [CI Skip] 0.95.2 2019-10-25 15:01:08 +00:00
Jaco Greeff 26be5e0cc5 0.95 nextIndex patch 2019-10-25 16:54:54 +02:00
Github Actions 66142c0137 [CI Skip] 0.96.0-beta.0 2019-10-25 14:28:45 +00:00
Jaco Greeff de395c7053 Skip nextIndex (#1513)
* Skip nextIndex

* Remove from derive
2019-10-25 16:22:06 +02:00
Github Actions ab78245576 [CI Skip] 0.95.1 2019-10-25 10:46:56 +00:00
Jaco Greeff 6ff0efca25 0.95 (#1512) 2019-10-25 12:40:21 +02:00
Github Actions fa0fd7140c [CI Skip] 0.95.0-beta.36 2019-10-25 06:57:58 +00:00
Jaco Greeff 0b71291cf1 Update latest extrinsic version (#1511)
* Update latest extrinsic version

* Don't export const with types
2019-10-25 08:51:03 +02:00
Github Actions 44d0ced5af [CI Skip] 0.95.0-beta.35 2019-10-24 14:34:28 +00:00
Jaco Greeff a8bfa90b87 Update signing comment (#1509)
* Update signing comment

* Extrinsic V4 CHANGELOG
2019-10-24 16:20:40 +02:00
Github Actions 835361d3c5 [CI Skip] 0.95.0-beta.34 2019-10-24 13:19:53 +00:00
Jaco Greeff 3bb719fcfc Extrinsic v4 (#1498)
* Extrinsic v4

* Comments

* V4 with MultiSignature

* Bump keyring with signature type indicator

* Return actual Signature type

* Update with MultiSignature enum

* Bump to stable common

* De-dup definitions somewhat
2019-10-24 15:13:03 +02:00
Github Actions 00a3001df9 [CI Skip] 0.95.0-beta.33 2019-10-23 15:49:30 +00:00
Jaco Greeff cac0056fc4 Allow user-define RPC interfaces (#1504)
* Allow user-define RPC interfaces

* Add user-decorated tests

* Pacify CC

* Typos

* Just push.
2019-10-23 17:36:27 +02:00
Github Actions a9e55e66d6 [CI Skip] 0.95.0-beta.32 2019-10-23 11:29:09 +00:00
Jaco Greeff c10f0e47b2 FAQ entry for tuple call (#1505)
* FAQ entry for tuple call

* Add default moral length
2019-10-23 13:22:13 +02:00
Github Actions 0b45bc6ab9 [CI Skip] 0.95.0-beta.31 2019-10-22 13:30:24 +00:00
Jaco Greeff 30f62f4024 Exclude build folders (#1503) 2019-10-22 15:23:47 +02:00
Github Actions 262f01b54e [CI Skip] 0.95.0-beta.30 2019-10-22 09:41:41 +00:00
Jaco Greeff 26c2774992 Bump dev deps (#1502) 2019-10-22 11:35:09 +02:00
Github Actions 58ff26cc78 [CI Skip] 0.95.0-beta.29 2019-10-21 15:36:21 +00:00
Jaco Greeff 62eab2d661 Fix returned accountId for derived staking.info (#1501) 2019-10-21 17:26:34 +02:00
Github Actions d4ab4f8293 [CI Skip] 0.95.0-beta.28 2019-10-21 14:25:19 +00:00
Jaco Greeff aed4b3ee6a Cleanup contracts type registry (#1497)
* Cleanup contracts type registry

* Remove some ! compiler overrides

* More mappy lookups

* Empty check
2019-10-21 16:18:41 +02:00
Github Actions 4c90c6158f [CI Skip] 0.95.0-beta.27 2019-10-20 10:04:04 +00:00
kwingram25 b911bdbd2d Add dynamic Vec ABI support (#1499) 2019-10-20 11:57:19 +02:00
Github Actions b5edcb8529 [CI Skip] 0.95.0-beta.26 2019-10-19 14:46:26 +00:00
Jaco Greeff 9086592252 Flatten encodeTypes, add missing BTreeMap (#1495)
* Flatten encodeTypes, add missing BTreeMap

* Fix param encoding
2019-10-19 16:39:53 +02:00
Github Actions c0b428dfbc [CI Skip] 0.95.0-beta.25 2019-10-18 12:51:38 +00:00
Jaco Greeff e49427ac61 Retrieve account.nextIndex via derive.balances.all (#1487)
* Retrieva account.nextIndex via derive.balances.all

* Remove unneeded cast

* Cast system.accountNonce

* Option -> null

* No undefined nonce
2019-10-18 14:45:25 +02:00
Github Actions 64149de2d4 [CI Skip] 0.95.0-beta.24 2019-10-17 13:29:23 +00:00
Jaco Greeff fe3de4379f Support TransactionPayment.{TransactionBaseFee, TransactionByteFee} (#1493)
* Support TransactionPayment.{TransactionBaseFee, TransactionByteFee}

* Dedup

* Ordering
2019-10-17 15:22:39 +02:00
Github Actions 5532daf640 [CI Skip] 0.95.0-beta.23 2019-10-16 13:11:35 +00:00
Jaco Greeff e197c6f114 Update shared-vec WASM (#1492) 2019-10-16 15:04:53 +02:00
Github Actions f3b71b21b5 [CI Skip] 0.95.0-beta.22 2019-10-16 08:20:10 +00:00
Jaco Greeff db3cb47d05 Firm up on derive typings & results (#1489)
* Firm up on derive typings & results

* Move assertion (eslint vs ts, round 1, fight!)
2019-10-16 10:13:13 +02:00
Github Actions 3f135f2da2 [CI Skip] 0.95.0-beta.21 2019-10-15 10:13:51 +00:00
Jaco Greeff 4ec6a0f9b8 Align doc headers & links (incl. api interface) (#1486) 2019-10-15 12:07:43 +02:00
Github Actions eca0d8d81a [CI Skip] 0.95.0-beta.20 2019-10-15 08:42:24 +00:00
Jaco Greeff e056675b3a Add raw RPC endpoints (#1485) 2019-10-15 10:36:15 +02:00
Github Actions 71a4b39698 [CI Skip] 0.95.0-beta.19 2019-10-14 11:23:40 +00:00
Jaco Greeff d194a6e4c9 Allow BTreeMap.with('u32', 'Text') (not only classes) (#1483) 2019-10-14 13:17:45 +02:00
Github Actions 4a7d8677a3 [CI Skip] 0.95.0-beta.18 2019-10-14 09:48:07 +00:00
Jaco Greeff 21ac0ac2fb Add TypeDefInfo handling for BTreeMap (#1481)
* Add TypeDefInfo handling for BTreeMap

* Update getTypeClass.ts

* Fixup BTreeMap result (will be active once class support is merged)

* Merge master, update with BTreeMap classes
2019-10-14 11:42:31 +02:00
Paul M FoxandJaco Greeff acfd856b25 Basic BTreeMaps codec support (#1474)
* BTreeMap codec type

* used proper, relative path

* Register class types by default

* reduced cognitive complexity

* Update packages/types/src/codec/BTreeMap.ts

Co-Authored-By: Jaco Greeff <jacogr@gmail.com>

* Update packages/types/src/codec/BTreeMap.ts

Co-Authored-By: Jaco Greeff <jacogr@gmail.com>

* Update packages/types/src/codec/BTreeMap.spec.ts

Co-Authored-By: Jaco Greeff <jacogr@gmail.com>

* added copyright; logic fixes

* added BTreeMap in alphabetical order

* better unit tests

multiple value examples taken from scale codec repo

* lint fix
2019-10-14 11:10:04 +02:00
Github Actions d5d8b59f8b [CI Skip] 0.95.0-beta.17 2019-10-12 14:06:12 +00:00
Jaco Greeff b24fe30a40 Split merge docs gen into sep process (#1482)
* Split merge docs gen into sep process

* Update doc refs
2019-10-12 16:00:22 +02:00
Github Actions 207e2982d7 [CI Skip] 0.95.0-beta.16 2019-10-12 09:34:53 +00:00
Jaco Greeff 6fab577e23 Expose hasSubscriptions on api rx interface (#1479) 2019-10-12 11:16:57 +02:00
扩散性百万甜面包 f7ca638a1a Minor class Events (#1478)
* Fix the return value as boolean on Event

* Minor class Events
2019-10-12 11:16:27 +02:00
Github Actions 0c96ba7a02 [CI Skip] 0.95.0-beta.15 2019-10-11 14:43:06 +00:00
Jaco Greeff 7143f5e643 Add new parathreads types (#1477)
* Add new parathreads types

* Fix dangling comma
2019-10-11 16:25:44 +02:00
Github Actions 910fa20b78 [CI Skip] 0.95.0-beta.14 2019-10-11 11:03:11 +00:00
Jaco Greeff 4855e631b5 Remove secret token from test step (#1475) 2019-10-11 12:44:52 +02:00
Jaco Greeff 698f2725c9 [CI Skip] 0.95.0-beta.13 2019-10-11 08:15:30 +00:00
Jaco Greeff 492fce1af7 Bump deps (#1472) 2019-10-11 09:58:00 +02:00
Jaco Greeff 397e9494eb [CI Skip] 0.95.0-beta.12 2019-10-11 07:50:34 +00:00
Jaco Greeff b8d7f4803b CHANGELOG (#1471) 2019-10-11 09:30:30 +02:00
Jaco Greeff 89f0d452f4 [CI Skip] 0.95.0-beta.11 2019-10-10 18:58:12 +00:00
Jaco Greeff bf8bed36ef Update drr equality (#1469)
* Update drr equality

* null === null

* Array length compare

* isFunction(next.eq)

* Just JSON.stringify on compare

* Add distinctUntilChanged in  rpc-core

* prev/next -> a/b
2019-10-10 20:41:57 +02:00
Jaco Greeff 38529ad13c [CI Skip] 0.95.0-beta.10 2019-10-10 16:49:38 +00:00
Jaco Greeff 8a6d23d461 Allow limited (non-sub operation) with Http provider (#1465)
* Allow limited (non-sub operation) with Http provider

* Throw-away typo
2019-10-10 18:28:15 +02:00
Jaco Greeff d80cc717e2 [CI Skip] 0.95.0-beta.9 2019-10-10 15:57:14 +00:00
Jaco Greeff a207348c13 Remove generated types from docs (#1468) 2019-10-10 17:35:21 +02:00
Jaco Greeff 4a795b4c50 [CI Skip] 0.95.0-beta.8 2019-10-10 15:22:27 +00:00
Jaco Greeff e54cee1fad Cleanup codec .skip tests (#1467) 2019-10-10 17:01:31 +02:00
Jaco Greeff 4e4108abfa [CI Skip] 0.95.0-beta.7 2019-10-10 14:52:30 +00:00
Jaco Greeff 3196e66efb Remove depcrecated addSignature (#1466) 2019-10-10 16:34:20 +02:00
Jaco Greeff 7e0f20908c [CI Skip] 0.95.0-beta.6 2019-10-10 11:18:34 +00:00
Jaco Greeff 985749ade1 Small typos (#1464) 2019-10-10 13:01:05 +02:00
Jaco Greeff ec8deb8be3 [CI Skip] 0.95.0-beta.5 2019-10-10 09:22:18 +00:00
Jaco Greeff b8d4bc5c6a Call.injectMetadata (align with Events) (#1462)
* Call.injectMetadata (align with Events)

* Fix interface builds

* Fix md builds

* Fixup tests with injection
2019-10-10 11:05:01 +02:00
Jaco Greeff 2870513453 [CI Skip] 0.95.0-beta.4 2019-10-09 13:38:10 +00:00
Jaco Greeff e27b35cd9f Merge branch 'master' of github.com:polkadot-js/api 2019-10-09 15:17:09 +02:00
Jaco Greeff bc86dbb31e Bump dev, gh-pages deploy 2019-10-09 15:17:06 +02:00
Jaco Greeff d1b047f675 [CI Skip] 0.95.0-beta.3 2019-10-09 12:49:13 +00:00
Jaco Greeff 8b43ee6ca1 Alias GH_TOKEN 2019-10-09 14:28:21 +02:00
Jaco Greeff f6e5068dae Swap CI to GH actions (#1460) 2019-10-09 14:22:00 +02:00
Jaco Greeff fe40e2378a Skip CI in actions (#1459) 2019-10-09 14:07:27 +02:00
Travis CI 2e9192ca02 [CI Skip] 0.95.0-beta.2 2019-10-08 14:51:58 +00:00
kwingram25 05ec4964fe Generate types from new contract ABI JSON (#1320)
* generate types from registry

* cleanup

* merge, rearrange

* lint

* built out

* abi v2 creation

* throw on unions

* linting

* version handling

* split functions

* cleanup

* drop v1 support

* special types

* changes

* requested changes

* formatTYpe

* rv outdated test

* rv union test

* codeclimate

* codeclimate

* codeclimate

* codeclimate

* codeclimate

* review

* cleanup encodeTypes

* fix option sub

* TypeDefInfo.Result
2019-10-08 16:31:48 +02:00
Travis CI 64f8444d47 [CI Skip] 0.95.0-beta.1 2019-10-08 13:24:45 +00:00
Jaco Greeff c0f9b45dca Bump deps (#1458) 2019-10-08 15:05:25 +02:00
Travis CI ffadc335d5 [CI Skip] 0.95.0-beta.0 2019-10-08 09:51:15 +00:00
Jaco Greeff 9c09386600 Support Metadata V8 (#1441)
* Support Metadata V8

* Update V7 references, introduce *Latest (as applicable)

* Add v8 static metadata

* Bump to latest metadata
2019-10-08 11:30:54 +02:00
Travis CI 7cc541c45f [CI Skip] 0.94.1 2019-10-07 15:09:27 +00:00
Jaco Greeff 2accd13bb6 0.94 (#1456) 2019-10-07 16:52:30 +02:00
Jaco Greeff 647e605c9f Rename push.yml to pr.yml 2019-10-07 16:14:15 +02:00
Travis CI eaa9dd00c7 [CI Skip] 0.94.0-beta.19 2019-10-07 14:02:41 +00:00
Jaco Greeff fb7e067737 Update Enum .eq to be more exhaustive (#1455)
* Update Enum .eq to be more exhaustive

* Add basic compare test
2019-10-07 15:31:05 +02:00
Jaco Greeff eaa71e0097 Action only on PR 2019-10-07 15:26:00 +02:00
Travis CI cd7767d39a [CI Skip] 0.94.0-beta.18 2019-10-07 11:58:10 +00:00
Jaco Greeff cf07d4f743 Add Result type (#1451)
* Add Result class

* Allow createType to operate on Result

* Formatting of Result type in interfaces (incl. use)

* Tests for Result

* Linting & createType seems to work, any final round of gaps?

* Bump metadata containing Result<Null,DispatchError>

* extractTypes handles Result (validation)

* Remove any from creation params

* Ok, give up trying to make `with` sane... it stays enum-like :(

* Move Enum protected decode member to file-level
2019-10-07 13:41:26 +02:00
Travis CI 525b6bf4ad [CI Skip] 0.94.0-beta.17 2019-10-07 11:29:30 +00:00
Jaco Greeff f73c01889f Run action on PR 2019-10-07 13:06:45 +02:00
Travis CI 56d20ceb41 [CI Skip] 0.94.0-beta.16 2019-10-06 12:08:32 +00:00
Jaco Greeff 25d1a1195e Expose api.createType (#1450) 2019-10-06 13:51:19 +02:00
Travis CI db593d2303 [CI Skip] 0.94.0-beta.15 2019-10-05 08:00:48 +00:00
Jaco Greeff e17572d845 Latest metadata (srml/utility) (#1448)
* Latest metadata (srml/utility)

* Move types to utility

* Add sample Kusama test

* Wrap in describeE2E

* Linting

* DispatchResult only in utility srml

* Fixup some tests (types at least)

* api-metadata tests
2019-10-05 09:42:45 +02:00
Travis CI 73704b68ab [CI Skip] 0.94.0-beta.14 2019-10-04 12:30:15 +00:00
Jaco Greeff d594149ed1 Fix derive heartbeats to query via index (#1446) 2019-10-04 14:13:06 +02:00
Travis CI 6b0e2fe919 [CI Skip] 0.94.0-beta.13 2019-10-04 10:04:33 +00:00
Jaco Greeff b36660a0cc Split actions (docs in own job) (#1445)
* Split actions (docs in own job)

* Update job names

* Rename action
2019-10-04 11:40:38 +02:00
Travis CI 29922c2bef [CI Skip] 0.94.0-beta.12 2019-10-04 07:52:35 +00:00
Jaco Greeff 1e67aeed9a Add GH actions (#1444) 2019-10-04 09:21:28 +02:00
Travis CI c28df79c3b [CI Skip] 0.94.0-beta.11 2019-10-03 21:03:46 +00:00
Jaco Greeff f145fe7c8b Fix isGenesisSlot (only on Babe) (#1443) 2019-10-03 22:46:31 +02:00
Travis CI a03a303b8f [CI Skip] 0.94.0-beta.10 2019-10-02 21:19:17 +00:00
Jaco Greeff eda93d25f6 Align CHANGELOG with current (#1438) 2019-10-02 23:00:56 +02:00
Travis CI 44d89ed204 [CI Skip] 0.94.0-beta.9 2019-10-02 19:40:33 +00:00
Jaco Greeff d632f25a9b Cloned API should filter RPCs (#1437) 2019-10-02 21:22:50 +02:00
Travis CI 2f6a397484 [CI Skip] 0.94.0-beta.8 2019-10-02 11:49:28 +00:00
Jaco Greeff a54286c98b Allow string (ss58) address input for approvalsOfAt (#1435)
* Allos string (ss58) address input for approvalsOfAt

* Rework deps
2019-10-02 13:31:04 +02:00
Travis CI ddd21c691f [CI Skip] 0.94.0-beta.7 2019-10-02 10:59:03 +00:00
Jaco Greeff d0f9114fda Don't decode and re-encode storage queries, single pass (#1433)
* Don't decode and re-encode storage queries, single pass

* Remove old SorageData <-> Bytes HACK tests

* Add non-empty check to isPendantic
2019-10-02 12:38:16 +02:00
Travis CI 275593b6fb [CI Skip] 0.94.0-beta.6 2019-10-02 10:32:50 +00:00
Jaco Greeff 17a10fbffe Allow approvalsOf to take string as "who" input (#1434)
* Allow approvalsOf to take string as "who" input

* Re-add <SetIndex> (build fails)
2019-10-02 12:15:50 +02:00
Travis CI afff880c20 [CI Skip] 0.94.0-beta.5 2019-10-01 20:39:36 +00:00
Joshy Orndorff 739625c171 Minor typo and grammar fixes. (#1431) 2019-10-01 22:21:59 +02:00
Travis CI 5fc8e3975b [CI Skip] 0.94.0-beta.4 2019-10-01 12:48:33 +00:00
Amaury Martiny fadb1ffdd8 Make derive types work, and a bit more readable (#1430)
* Fix typings for derive

* Fix typings

* Spacing
2019-10-01 14:30:53 +02:00
Travis CI bddb48f452 [CI Skip] 0.94.0-beta.3 2019-09-30 13:05:11 +00:00
Jaco Greeff af682bc23b Custom extrinsic formats (docs) (#1429)
* Custom extrinsic formats (docs)

* Typos

* Typos (other docs)
2019-09-30 14:42:06 +02:00
Travis CI 7b2cf6dcb0 [CI Skip] 0.94.0-beta.2 2019-09-30 12:41:49 +00:00
Amaury Martiny 9807ff70fa Fix api.derive missing typings (#1428)
* Use @polkadot/types imports everywhere

* use t for all interfaces

* Add comment
2019-09-30 14:24:01 +02:00
Travis CI d30bd0dd86 [CI Skip] 0.94.0-beta.1 2019-09-28 08:00:59 +00:00
Jaco Greeff 25f78a7354 Stringify error data structs (#1426) 2019-09-28 09:44:35 +02:00
Travis CI 0bc0ef6110 [CI Skip] 0.94.0-beta.0 2019-09-27 14:48:55 +00:00
Stefanie Doll b231b7b8cb Rename types in docs to match exports (#1424) 2019-09-27 16:32:11 +02:00
364 changed files with 20734 additions and 3548 deletions
+1 -1
View File
@@ -1 +1 @@
6
8
-24
View File
@@ -1,24 +0,0 @@
version: 2
jobs:
build:
branches:
ignore:
- gh-pages
working_directory: ~/polkadot-js
docker:
- image: circleci/node:10
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "yarn.lock" }}
- run:
name: install-deps
command: yarn install --frozen-lockfile
- save_cache:
key: dependency-cache-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- ~/.cache/yarn
- run:
name: build
command: yarn polkadot-dev-circleci-build
+1 -1
View File
@@ -5,7 +5,7 @@ module.exports = {
parserOptions: {
...base.parserOptions,
project: [
'./tsconfig.eslint.json'
'./tsconfig.json'
]
},
rules: {
+71
View File
@@ -0,0 +1,71 @@
name: PR
on: [pull_request]
jobs:
lint:
name: Linting
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: lint
run: |
yarn install --frozen-lockfile
yarn lint
test:
name: Testing
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: test
run: |
yarn install --frozen-lockfile
yarn test
build_code:
name: Build Code
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: build
run: |
yarn install --frozen-lockfile
yarn build
build_docs:
name: Build Docs
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: build
run: |
yarn install --frozen-lockfile
yarn docs
+55
View File
@@ -0,0 +1,55 @@
name: Master
on:
push:
branches:
- master
jobs:
build_code:
name: Build Code
if: "! contains(github.event.head_commit.message, '[CI Skip]')"
runs-on: ubuntu-latest
strategy:
matrix:
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:
node-version: ${{ matrix.node-version }}
- name: build
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
GH_PAT: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ secrets.GH_PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
yarn install --frozen-lockfile
yarn polkadot-dev-ghact-build
build_docs:
name: Build Docs
if: "! contains(github.event.head_commit.message, '[CI Skip]')"
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: build
env:
GH_PAT: ${{ secrets.GH_PAT }}
GH_TOKEN: ${{ secrets.GH_PAT }}
GH_PAGES_SRC: build-docs
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
yarn install --frozen-lockfile
yarn polkadot-dev-ghact-docs
-28
View File
@@ -1,28 +0,0 @@
language: node_js
node_js:
- "10"
env:
global:
- CC_TEST_REPORTER_ID=b8983d04997f43ff9b9df9aa92904967547680e2a229af812b3cf14985713e84
- GH_PAGES_SRC="build-docs"
cache:
yarn: true
directories:
- node_modules
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- export PATH=$HOME/.yarn/bin::$(yarn global bin):$PATH
before_script:
- ./cc-test-reporter before-build
script:
- yarn polkadot-dev-travis-build
after_script:
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
deploy:
skip_cleanup: true
provider: script
script: yarn polkadot-dev-travis-deploy
on:
branch: master
+47 -11
View File
@@ -1,3 +1,39 @@
# 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)
- Adjust subscription update checks to avoid duplicated data updates
- Support Metadata V8 (exposes per-module `decl_error` definitions)
- Support next generation contracts ABI (with additional type definitions)
- Support for `BTreeMap<K, V>` types and definitions
- All latest Polkadot & Substrate types (as per master branches)
- **Breaking change** `Call.injectMethods` is moved to `Call.injectMetadata` to align with `Events` (This _should_ not be used externally, however mentioned as breaking here)
# 0.94.1
- Add handling of `Result<Ok, Error>` definitions
- Adjust API cloning now takes RPC filters from source into account
- Simplification of isPedantic checks and less overhead on StorageData types
- Cleanups and fixes around RPC and derive type definitions
- Fix `derive.imOnline.receivedHeatbeats` to query via indexes
- Adjustment of `api.derive.elections.{approvalsOf|approvalsOfAt}` to allow ss58 address input
- Cleanup `Enum` `.eq` handling to be more exhaustive
- Add documentation for custom extrinsic formats (advanced chains)
- Update to latest substrate master metadata
# 0.93.1
- Support for Kusama CC2
@@ -23,7 +59,7 @@
- The `getRuntimeVersion` and `subscribeRuntimeVersion` RPCs are now only available on the `rpc.state.*` endpoints. This aligns with the Substrate implementation.
- The `author_insertKey` RPC's last argument `publicKey` is now required, as to reflect Substrate implementation.
- Support for extrinsics with versions that is not in the base Substrate implementation (V1-V3) can now be done by providing an implementation for `ExtrinsicUnknown`
- Redeemed balance calculation if `api.derive` now returns the correct values again (bugfix)
- Redeemed balance calculation if `api.derive` now returns the correct values again (bug fix)
- added the `yarn chain:info [--ws URL]` utility to extract a calls-only metadata version
- Missing types are now logged via a `console.warn`, not via `.error`
- `Extrinsic`, `ExtrinsicPayload` & `SignerPayload` is registered in the type registry and can be overriden now
@@ -39,7 +75,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
- **Breaking change** `Api.create(...)` and `new Api(...)` now only takes an options Object, so if you passed the provider directly previously, you need to swap the use to `Api.create({ provider: ... })`
- **Breaking change** Runtime types have been extended and moved to definitions instead of classes
- Primitive types for `i*` and `u*` (e.g. `u32`) are now only available in their lowercase versions. Additionally `Vector` is now only available as `Vec`, and `Method` has been renamed to `Call`, in both cases aligning with Rust.
- `Moment` now implements as `u64` as per the Substrate codebase. (It it up to the user to interpret, for substrate 2.x it is not mili-second resolution)
- `Moment` now implements as `u64` as per the Substrate codebase. (It it up to the user to interpret, for substrate 2.x it is not ms resolution)
- For creation of types, it is recommended to use `createType(<TypeName>, <value>)` instead of e.g. `new Proposal(...)`. When passing these to methods/queries, construction should not be needed, the raw value can be passed.
- For moved types, a previous import would have been from `@polkadot/types`, i.e. `import { SetIndex } from '@polkadot/types`, now just the interfaces (TypeScript) are available via `import { SetIndex } from '@polkadot/types/interfaces`
- `usize` is now a blacklisted type that will throw on construction. Since it is platform-specific, it creates incompatibilities between native (generally `u64`) and WASM (always `u32`) code. Use one of the `u32` or `u64` types explicitly.
@@ -123,7 +159,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
# 0.77.1
- Support Metadata v4, which introduces the use of a custom hasher to hash storage map keys.
- Add TresuryProposal (not the same as democracy, type aliassed)
- Add TreasuryProposal (not the same as democracy, type aliased)
# 0.76.1
@@ -145,7 +181,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
- For extrinsic status results, if you have checked the type returns, i.e. `result.type === 'Finalised'` now check on the status for `result.status.isFinalized` or `result.status.isBroadcast`, ... (the `type` property is now accessible only on `result.status.type`)
- If using `subscribeFinalisedHeads` update this to `subscribeFinalizedHeads` (likewise `getFinalisedHead` should be updated to `getFinalizedHead` and `derive.bestNumberFinalized`)
- The underlying ss58 addess checksums have changed
- The underlying ss58 address checksums have changed
- The updated keyring with support for this has been made available
- All examples have been updated with sr25519 addresses (with the new checksums)
@@ -163,12 +199,12 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
# 0.51.1
- Support metadata V2 as per latest substrate master
- Update metadata with new types as per lastest substrate master
- Update metadata with new types as per latest substrate master
# 0.50.1
- Lastest util-crypto (usage of WASM with JS fallbacks if not available)
- Latest util-crypto (usage of WASM with JS fallbacks if not available)
- Update upstream @polkadot dependencies (for new crypto)
@@ -191,7 +227,7 @@ If you are upgrading form an older version, use the CHANGELOG hand-in-hand with
# 0.46.1
- Extended type registration to now handle internal types as well. Additionally the built-in Extrinsic type can now we overridden with a custom version.
- Where `Extrinsic` and `Method` is used as types, considder importing `{ IMethod, IExtrinsic }` from `@polkadot/types/types`, especially in the cases where this is uased from a `SubmittableExtrinsic`
- Where `Extrinsic` and `Method` is used as types, consider importing `{ IMethod, IExtrinsic }` from `@polkadot/types/types`, especially in the cases where this is used from a `SubmittableExtrinsic`
- The `typeRegistry` constant is now `getTypeRegistry()` as a function
@@ -214,7 +250,7 @@ console.log('llo', llo.unwrapOr('not set') /* Option<BlockNumber> */)
# 0.44.1
- Split primitives and types into seperate folders. This should not affect external use since the exports remain the same, however does have an impact where classes are referenced directly. e.g.
- Split primitives and types into separate folders. This should not affect external use since the exports remain the same, however does have an impact where classes are referenced directly. e.g.
```js
// old (affected)
@@ -232,7 +268,7 @@ import { Method, Signature } from '@polkadot/types';
# 0.43.1
- Intrduces support for the new keyring with sr25519 support in addition to ed25519. While this does not change the exposed API, it is considerred breaking since @polkadot/keyring has interface changes. (Unless needed, don't rush the upgrade)
- Introduces support for the new keyring with sr25519 support in addition to ed25519. While this does not change the exposed API, it is considered breaking since @polkadot/keyring has interface changes. (Unless needed, don't rush the upgrade)
# 0.42.1
@@ -243,7 +279,7 @@ import { Method, Signature } from '@polkadot/types';
# 0.41.1
- Support the V1 metadata specification from Substrate in addition to the currently testnet-active V0 version
- Support the V1 metadata specification from Substrate in addition to the currently testnet active V0 version
# 0.40.1
@@ -263,7 +299,7 @@ Substrate has been updated with a breaking new transaction format where the Inde
# 0.37.1
api-observable has been removed. This was only used in /apps and inconsistent with the api/rx and api/promise APIs. Future work will include derivates like was included in api-observable into the base.
api-observable has been removed. This was only used in /apps and inconsistent with the api/rx and api/promise APIs. Future work will include derives like was included in api-observable into the base.
Tuples now return single types when only one type is available, i.e. `(AccountId)` would now resolve as `AccountId`. The extra type wrapper adds no benefit to users here.
+1
View File
@@ -43,6 +43,7 @@ module.exports = {
['start/api.tx.wrap.md', 'Complex transactions'],
['start/types.basics.md', 'Type basics'],
['start/types.extend.md', 'Extending types'],
['start/extrinsic.extend.md', 'Extending extrinsics'],
['start/typescript.md', 'TypeScript interfaces'],
['start/FAQ.md', 'FAQ']
]
+1 -1
View File
@@ -46,7 +46,7 @@
- [Unsubscribe from listening](examples/promise/04_unsubscribe/README.md)
- [Read chain state](examples/promise/05_read_storage/README.md)
- [Make a transfer](examples/promise/06_make_transfer/README.md)
- [Display system events](examples/promise/08_system_events/README.md)(
- [Display system events](examples/promise/08_system_events/README.md)
- [Transaction with events](examples/promise/09_transfer_events/README.md)
- [Upgrade via sudo](examples/promise/10_upgrade_chain/README.md)
- [ApiRx](examples/rx/README.md)
@@ -2,4 +2,4 @@
In addition to querying the latest storage, you can make storage queries at a specific blockhash. Be aware that the node applies a pruning strategy and typically only keeps the last 256 blocks, unless run in archive mode.
<<< @/docs/examples/promise/07_read_storage_at/index.js
<<< @/docs/examples/promise/05_read_storage_at/index.js
@@ -2,4 +2,4 @@
This example shows how to instantiate a Polkadot API object and use it to connect to a node and retrieve balance updates.
<<< @/docs/examples/rx/03_listent_to_balance_change/index.js
<<< @/docs/examples/rx/03_listen_to_balance_change/index.js
+10
View File
@@ -23,3 +23,13 @@ As of this writing we don't have an explicit example of implementing the signer
Some calls in Polkadot/Substrate can only be submitted as root, these are indicated by `ensure_root(origin)` in the Rust codebase. Root here does not refer to the actual account, i.e. `//Alice` on a `--dev` chain, but rather that it cannot be submitted as a bare user transaction. This restriction applies to chain upgrades, changing balances or anything that modifies the state and/or chain operation.
To submit these transactions, it needs to be send as a [wrapped transaction](api.tx.wrap.md#sudo-use) via either `sudo.sudo` (assuming you have access on your chain) or `democracy.proposal` (which would allow users of the chain to vote on it).
## How do I call a function with a Tuple input
Tuples, as defined in the Polkadot/Substrate types appear as `(TypeA, TypeB)`. For instance we may have an `(AccountId, u64)` input as defined in the metadata or as part of the user types. To specify a Tuple as an input, wrap it is an array format, for instance to call `query.module.get((u32, u64))` where a `(u32, u64)` Tuple input is expected, you would do `query.module.get([123, 456])`
## How long do transactions live
Polkadot/Substrate supports both immortal and mortal transactions. For immortal, this means that the transaction has an infinite lifetime, for mortals, the transactions expire after a defined period. By default the API sends mortal transactions when no explicit extrinsic era has been specified. This means that all transaction has a limited lifetime and will expire if not included in the period set.
The length for this transaction validity is set to 50 blocks, which translates to 5 minutes assuming a default of 6 second blocktimes. (10 blocks per minute in this default configuration).
+2 -2
View File
@@ -33,7 +33,7 @@ const momentPrev = await api.query.timestamp.now.at(lastHdr.parentHash);
The `.at` queries are all single-shot, i.e. there are no subscription option to these, since the state for a previous block should be static. (This is true to a certain extent, i.e. when blocks have been finalized).
An additional point to take care of (briefly mentioned above), is state pruning. By default a Polkadot/Substrate node will only keep state for the last 256 blocks, unless it is explicitly run in archive mode. This means that querying state further back than the pruning period will result in an error returned from the Node. (Generaly most public RPC nodes only run with default settings, which includes aggressive state pruning)
An additional point to take care of (briefly mentioned above), is state pruning. By default a Polkadot/Substrate node will only keep state for the last 256 blocks, unless it is explicitly run in archive mode. This means that querying state further back than the pruning period will result in an error returned from the Node. (Generally most public RPC nodes only run with default settings, which includes aggressive state pruning)
## State entries
@@ -69,7 +69,7 @@ console.log(`query key: ${api.query.balances.freeBalance.key(ADDR)}`);
The `section` & `method` is an indication of where it is exposed on the API. In addition the `meta` holds an array with the metadata documentation for the entry.
The `key` endpoint requires some explanation. In the chain state, the key values (identified by the module, method & params) are hashed and this is used as a lookup. So underlying a single-shot query would utilize the `api.rpc.state.getStorage` entry, passing the output of `key` (which is a hashed representation of the values). Apart from the hashing, the API also takes care of type formatting, handling optional values and merging results accross multiple subscriptions.
The `key` endpoint requires some explanation. In the chain state, the key values (identified by the module, method & params) are hashed and this is used as a lookup. So underlying a single-shot query would utilize the `api.rpc.state.getStorage` entry, passing the output of `key` (which is a hashed representation of the values). Apart from the hashing, the API also takes care of type formatting, handling optional values and merging results across multiple subscriptions.
## Let's transact already!
+1 -1
View File
@@ -2,7 +2,7 @@
Previously we explained the concepts between `api.query`. In this section we will expand on that knowledge to introduce subscriptions (akin to what we found in `api.rpc`) to stream results from the state, as it changes between blocks.
## Subcriptions
## Subscriptions
As in the case with `api.rpc` subscriptions, query subscriptions follow exactly the same form - an actual call is augmented with a callback to return the current state value that is updated as the underlying value changes. As an example, we can extend on what we had previously -
+1 -1
View File
@@ -29,7 +29,7 @@ The result for this call (we will deal with subscriptions in a short while), is
Despite the single-line format of `signAndSend`, there is a lot happening under the hood (and all of this can be manually provided) -
- Based on the sender, the API will retrieve the `system.accountNonce` to determine the next nonce to use
- The API will retrieve the current block hash and use it to create a mortal transaction, i.e. the transaction will only be valid for a limited number of blocks (by default this is 5 mins at 6s blocktimes)
- The API will retrieve the current block hash and use it to create a mortal transaction, i.e. the transaction will only be valid for a limited number of blocks (by default this is 5 mins at 6s block times)
- It will construct a payload and sign this, this includes the `genesisHash`, the `blockHash` for the start of the mortal era as well as the current chain `specVersion`
- The transaction is submitted to the node
+2 -2
View File
@@ -1,6 +1,6 @@
# Complex transactions
Up till now we have focussed on the base operation of transactions. There are however some more complex operations that deserve some more information, for instance when doing either democracy proposals or excuting sudo calls, in both these cases the transaction wraps a call or proposal to be evaluated.
Up till now we have focussed on the base operation of transactions. There are however some more complex operations that deserve some more information, for instance when doing either democracy proposals or executing sudo calls, in both these cases the transaction wraps a call or proposal to be evaluated.
## Sudo use
@@ -41,4 +41,4 @@ In the above example, all we need to provide is a the fields for the `ValidatorP
## Understanding types
As has been very apparent in all the preceding sections, the management of types is what allows the API to communicate with the node. Most values are in a [binary SCALE-encoded format](https://github.com/paritytech/parity-scale-codec) and it is the reponsibility of the API is to encode and decode these. In the next section we will [take a look at what interfaces the API provides around types](types.basics.md).
As has been very apparent in all the preceding sections, the management of types is what allows the API to communicate with the node. Most values are in a [binary SCALE-encoded format](https://github.com/paritytech/parity-scale-codec) and it is the responsibility of the API is to encode and decode these. In the next section we will [take a look at what interfaces the API provides around types](types.basics.md).
+1 -1
View File
@@ -16,7 +16,7 @@ Additionally the metadata also provides information on [events](../substrate/eve
## Types
The metadata defiends the calls with all the type names used in the various interfaces. At the moment (this is undergoing investigations and could improve in future versions of metadata), this also means that the types between the API and the node need to be aligned. For instance, by default Substrate defines a `BlockNumber` type as a `u32` and the API follows the Substrate defaults - if a chain has a different definitions, the API needs to be aware of this so it can actually decode (and encode) the type.
The metadata defines the calls with all the type names used in the various interfaces. At the moment (this is undergoing investigations and could improve in future versions of metadata), this also means that the types between the API and the node need to be aligned. For instance, by default Substrate defines a `BlockNumber` type as a `u32` and the API follows the Substrate defaults - if a chain has a different definitions, the API needs to be aware of this so it can actually decode (and encode) the type.
At this point just be aware of it, we will touch on types, custom chains and their impacts in a later section.
+1 -1
View File
@@ -15,7 +15,7 @@ const api = await ApiPromise.create({ provider: wsProvider });
console.log(api.genesisHash.toHex());
```
We will have some explanation on the ES2015 syntax used next, but just a small note on the above - where other code is included (or just some previous boilerplate is used), you will see `...` in most of the examples. This is not due to lazyness, but rather just to keep things straight and to the point.
We will have some explanation on the ES2015 syntax used next, but just a small note on the above - where other code is included (or just some previous boilerplate is used), you will see `...` in most of the examples. This is not due to laziness, but rather just to keep things straight and to the point.
## ES2015 Usage and examples
+158
View File
@@ -0,0 +1,158 @@
# Extending extrinsics
On some chains, the need may arise to customize the extrinsic format. In this section we will explain what extrinsics and their payloads contain, explain how signed extensions work and provide a walk through of an advanced use-case where extrinsics are customized for a specific Substrate chain.
## Extensions
In Substrate (which forms the base of Polkadot and a number of custom chains), an extrinsic has a specific version, flag to indicating if it has been signed, the address, signature, extra data as well as the actual method with params. In addition, the signature is generated over the call and may include values that are not encoded into the final extrinsic.
For instance, with version 3 extrinsics, the signature payload contains the runtime spec version as well as the `genesisHash` and `blockHash` (the latter being equivalent to the `genesisHash` in case of immortal transactions), however while these 3 fields are signed together with the method data, they do not actually appear in the extrinsic itself. Rather the chain executing the transaction will retrieve this information, add it to the method data and compare the signatures thereof.
So in both the cases of the `genesisHash` and `specVersion`, if these do not match the signer version, the transaction won't be accepted - however the extrinsic doesn't explicitly carry this information in the data being transmitted, rather only implicitly as part of the signature. And it always forms part of the validation.
## Default extrinsics
With the above in-mind, the extrinsic format is explicitly defined as having the following structure in Substrate -
```rust
pub struct UncheckedExtrinsic<Address, Call, Signature, Extra>
where Extra: SignedExtension
{
pub signature: Option<(Address, Signature, Extra)>,
pub function: Call,
}
```
The `Option` is here encoded such that is conveys both the extrinsic version `0x03` for Substrate 2.x chains (`0x01` for Substrate 1.x chains) as well as a high-bit that indicates if the transaction is signed or unsigned. (For unsigned the `signature` details therefore does not appear). The `SignedExtension` part defined both the data in the actual extrinsic as well as data, i.e. `AdditionalSigned`, that appears in the payload for the signature, but is not explicitly contained in the extrinsic.
The default `SignedExtension` for Substrate 2.x with extrinsic version 3 is defined as follow -
```rust
pub type SignedExtra = (
system::CheckVersion<Runtime>,
system::CheckGenesis<Runtime>,
system::CheckEra<Runtime>,
system::CheckNonce<Runtime>,
system::CheckWeight<Runtime>,
balances::TakeFees<Runtime>,
contracts::CheckBlockGasLimit<Runtime>,
);
```
Some of these are only checks, requiring no additional data in the payload or extrinsic itself, i.e. the contracts checks do exactly that. It only applies checks and invalidates when those checks are invalid. This is a powerful concept, for instance on the [initial Kusama chain this was used to limit the types of calls allowed](https://github.com/paritytech/polkadot/blob/f52c714ec3411eea58647d0f5176f4eb81660188/runtime/src/lib.rs#L117-L139).
## Extension deep-dive
For each of the default extensions, we will take a look through to understand the implications of the specific extension and how it relates to both the data contained in the extrinsic as well as the signature payload.
- `system::CheckVersion` - This checks that the spec version matches between the extrinsic and the chain. It takes no parameters which means that these is no explicit data in the extrinsic format for this field, however it has `type AdditionalSigned = u32` which means that a `u32` containing the runtime spec version is part of the signature payload.
- `system::CheckGenesis` - This checks that the `genesisHash` matches between extrinsic and chain. Like the previous check, no additional data is added to the extrinsic, however with `type AdditionalSigned = T::Hash`, the `genesisHash` is part of the signature payload.
- `system::CheckEra` - This checks the era (mortal or immortal) for the transaction being sent. It checks both the `era: Era` as part of the actual extrinsic and the `blockHash` via the `type AdditionalSigned = T::Hash`. This means that the extrinsic era is both in the data being signed and the extrinsic itself, while the `blockHash` the era applies to is only available in the signature payload.
- `system::CheckNonce` - This checks the nonce for the sending account. Unlike the preceding checks, it has no payload-specific data, however the `nonce: Compact<T::Index>` (`Index` is default `u32`) is applicable to both the extrinsic and, therefore, the actual signature payload as well.
- `system::CheckWeight` - This checks the weight and length of the block and ensure that it does not exceed the limits. It does not have any specific data attached to either the extrinsic nor payload, but rather just does calculations based on the weights and type of transaction received.
- `balances::TakeFees` - Consumes fees proportional to the length and weight of the transaction. It operates on the `fee: Compact<T::Balance>`, which means this value is included in both the extrinsic and subsequent payload being signed.
- `contracts::CheckBlockGasLimit` - As explained briefly above, this extension does not add data to the extrinsic, or the signature payload, however it ensures that the transaction does not exceeds the block gas limit.
## Extrinsic and signature payloads
With the above extension, the following formats for the extrinsic and payloads are the outcome of the application of the signed extension. For the extrinsic the following data is [always encoded for v3 extrinsics](https://github.com/polkadot-js/api/blob/8b0ef159c05bcb5d9b664546d0e7289e79b5c9d5/packages/types/src/primitive/Extrinsic/v3/Extrinsic.ts#L27) -
```js
class ExtrinsicV3 extends Struct {
constructor (value) {
super({
signer: 'Address',
signature: 'Signature',
era: 'ExtrinsicEra', // extra via system::CheckEra
nonce: 'Compact<Index>', // extra via system::CheckNonce
tip: 'Compact<Balance>', // extra via balances::TakeFees
method: 'Call'
}, value);
}
...
```
The signature payload will contain the same information as the extrinsic, with the following [additional information](https://github.com/polkadot-js/api/blob/8b0ef159c05bcb5d9b664546d0e7289e79b5c9d5/packages/types/src/primitive/Extrinsic/v3/ExtrinsicPayload.ts#L33) as expected by the `AdditionalSigned` portions of the extensions -
```js
class ExtrinsicPayloadV3 extends Struct {
constructor (value) {
super({
method: 'Bytes',
era: 'ExtrinsicEra', // extra via system::CheckEra
nonce: 'Compact<Index>', // extra via system::CheckNonce
tip: 'Compact<Balance>', // extra via balances::TakeFees
specVersion: 'u32', // additional via system::CheckVersion
genesisHash: 'Hash', // additional via system::CheckGenesis
blockHash: 'Hash' // additional via system::CheckEra
}, value);
}
...
```
As per the above structures, it means that both the extrinsic sent on-chain as well as the data being signed to generate the signature is tied by the hip based on the logic the chain expects via `SignedExtension`. The API is only aware of the version of the extrinsic being used on-chain (it determines this on connection) and therefore only knows about the specific logic that has been coded for the extrinsic version.
## Extending existing or implementing new
When the API encodes or decodes an extrinsic, it uses the first `Option` byte to determine the version. Once it has this value, it will create a specific extrinsic via `createType('ExtrinsicV3', value)`. This means that at any point, you can supply your own version of either the `Extrinsic` or `ExtrinsicPayload` and you can do so via 2 avenues -
- If you are extending/replacing the existing version, you can inject your own types for both `ExtrinsicV3` and `ExtrinsicV3Payload` (assuming you are replacing v3)
- If you are adding a new version, you can add a handler for both `ExtrinsicUnknown` and `ExtrinsicPayloadUnknown`. These will be constructed when the version the API is aware of does not match with the on-chain version.
While we will not provide a full example of all the code here, the above links will show the existing implementations. However, assuming we have a chain where neither the nonce or tip is applicable (or we just don't care) and we are ignoring the check to the runtime versioning.
Additionally assuming that we have made the required `SignedExtension` updates by removing `system::CheckVersion`, `system::CheckNonce` and `balances::TakeFees`, we can do the following -
```js
...
class OwnExtrinsic extends Struct {
constructor (value) {
super({
signer: 'Address',
signature: 'Signature',
era: 'ExtrinsicEra', // extra via system::CheckEra
method: 'Call'
}, value);
}
...
}
class OwnExtrinsicPayload extends Struct {
constructor (value) {
super({
method: 'Bytes',
era: 'ExtrinsicEra', // extra via system::CheckEra
genesisHash: 'Hash', // additional via system::CheckGenesis
blockHash: 'Hash' // additional via system::CheckEra
}, value);
}
...
// signing logic needs to be included, as per existing
}
...
// inject our types at API construction
const api = ApiPromise.create({
types: {
'ExtrinsicV3': OwnExtrinsic,
'ExtrinsicV3Payload': OwnExtrinsicPayload,
}
})
```
The above example is certainly an advanced example, but it shows that all data types in the API can be adjusted and these adjustment can be provided to the API. In all cases, if you made updates to the formats and types of the actual runtime, you need to ensure that the API is aware of these changes.
In the above example, should these updates only be made on the node side, without the required API adjustments, the API will generate invalid transactions for the node since it is unaware of the changes and adjusted formats. Making the adjustments on only one side will mean that the signature verification can fail and that the format will not be decodable via the node.
(These extensions are not exposed via metadata at all, and would be quite difficult to do as well - since each of these have specific logic as well as data types assigned.)
## Using with TypeScript
The API is built with TypeScript (as are all projects in the [polkadot-js organization](https://github.com/polkadot-js/)) and as such allows developers using TS to have access to all the type interfaces defined on the chain, as well as having access to typings on interacting with the `api.*` namespaces. In the next section we will provide an overview of [what is available in terms of types and TypeScript](typescript.md).
+2 -2
View File
@@ -4,11 +4,11 @@ Yes, it really is as simple as [installing from npm](https://www.npmjs.com/packa
`yarn add @polkadot/api`
And it will be added and ready for use. The above will always install the latest stable release, which should allow you to connect to testsnets and local nodes that are tracking versioned releases for [Polkadot](https://github.com/paritytech/polkadot) and [Substrate](https://github.com/paritytech/substrate).
And it will be added and ready for use. The above will always install the latest stable release, which should allow you to connect to test networks and local nodes that are tracking versioned releases for [Polkadot](https://github.com/paritytech/polkadot) and [Substrate](https://github.com/paritytech/substrate).
## Betas
For users who have a slightly higher appetite for risk, or are using bleeding-edge master branches of either Polkadot/Substrate, we also publish a beta version as soon as anything is merged into the API master branch. This version really contains all the latest fixes and features and is the version we actually use inside the polkadot-js projects - eating our own dogfood.
For users who have a slightly higher appetite for risk, or are using bleeding-edge master branches of either Polkadot/Substrate, we also publish a beta version as soon as anything is merged into the API master branch. This version really contains all the latest fixes and features and is the version we actually use inside the polkadot-js projects - eating our own dog food.
To install a beta version, either to test or for support of a feature that is available in Substrate master (and has not yet made it to a stable api release), you can install it via the `@beta` tag, i.e.
+4 -4
View File
@@ -6,7 +6,7 @@ This section will give a quick introduction into the Keyring, including the addi
They [@polkadot/keyring](https://github.com/polkadot-js/common/tree/master/packages/keyring) keyring is included directly with the API as a dependency, so it is directly importable (since the 0.92 version) alongside the API.
If you do opt to install it seperately, ensure that the version of `@polkadot/util-crypto` that is included with the API matches with the version of `@polkadot/keyring` installed. So if the API depends on `util-crypto 1.4.1`, it would make sense to include `keyring 1.4.1` as the installed version. (This helps in making sure extra versions of the libraries are not included as duplicates, especially in the case where bundles are created. Additionally, this makes sure that weird side-effects in the WASM initialization is avoided.)
If you do opt to install it separately, ensure that the version of `@polkadot/util-crypto` that is included with the API matches with the version of `@polkadot/keyring` installed. So if the API depends on `util-crypto 1.4.1`, it would make sense to include `keyring 1.4.1` as the installed version. (This helps in making sure extra versions of the libraries are not included as duplicates, especially in the case where bundles are created. Additionally, this makes sure that weird side-effects in the WASM initialization is avoided.)
## Creating a keyring instance
@@ -27,7 +27,7 @@ In the above example, the import is self-explanatory. Upon creation we pass thro
So effectively, when creating an account and not specifying a type, it will be `sr25519` by default based on the above construction params, however we can also add an `ed25519` account and use it transparently in the same keyring.
One "trick" that is done implictly in the above sample is that that keyring is only initialized after the API. In the case of `sr25519` the keyring relies on a [WASM build](https://github.com/polkadot-js/wasm) of the [schnorrkel libraries](https://github.com/w3f/schnorrkel). Since the API inlitialization is already async, it initializes the WASM libraries are part of the setup.
One "trick" that is done implicitly in the above sample is that that keyring is only initialized after the API. In the case of `sr25519` the keyring relies on a [WASM build](https://github.com/polkadot-js/wasm) of the [schnorrkel libraries](https://github.com/w3f/schnorrkel). Since the API inlitialization is already async, it initializes the WASM libraries are part of the setup.
However, this initialization can also be done explicitly, mostly for more advances use-cases, or in cases where the API won't be attached until much later -
@@ -52,7 +52,7 @@ The recommended catch-all approach to adding accounts is via `.addFromUri(<suri>
// Some mnemonic phrase
const PHRASE = 'entire material egg meadow latin bargain dutch coral blood melt acoustic thought';
// Add an account, straight menemonic
// Add an account, straight mnemonic
const newPair = keyring.addFromUri(PHRASE);
// (Advanced) add an account with a derivation path (hard & soft)
@@ -62,7 +62,7 @@ const newDeri = keyring.addFromUri(`${PHRASE}//hard-derived/soft-derived`);
const alice = keyring.addFromUri('//Alice', { name: 'Alice default' });
```
The above additions cater for most of the usecases and aligns with the you would find in the Substrate `subkey`. Be very wary of the last "dev-seed" option, it is explicitly added for `subkey` compatibility and implies using the "known-everywhere" dev seed. It is however useful when running Polkadot/Substrate with a `--dev` flag.
The above additions cater for most of the use cases and aligns with the you would find in the Substrate `subkey`. Be very wary of the last "dev-seed" option, it is explicitly added for `subkey` compatibility and implies using the "known-everywhere" dev seed. It is however useful when running Polkadot/Substrate with a `--dev` flag.
## Adding accounts with raw seeds
+3 -3
View File
@@ -4,7 +4,7 @@ We've touched upon types in most previous sections, i.e. that these are driven b
## Everything is a type
Just to re-iterate from the above. Eveything returned by the API is a type and has a consistent interface. This means that a `Vec<u32>` (an array of `u32` values) as well as a `Struct` (an pre-defined object) or an `Enum` has the same consistent base interface. Specific types types will have values, based on the type - decorated and available.
Just to re-iterate from the above. Everything returned by the API is a type and has a consistent interface. This means that a `Vec<u32>` (an array of `u32` values) as well as a `Struct` (an pre-defined object) or an `Enum` has the same consistent base interface. Specific types types will have values, based on the type - decorated and available.
As a minimum, anything returned by the API, be it a `Vec<...>`, `Option<...>`, `Struct` or any normal type will always have the following methods -
@@ -16,7 +16,7 @@ As a minimum, anything returned by the API, be it a `Vec<...>`, `Option<...>`, `
Additionally, the following getters and utilities are available -
- `.isEmpty` - `true` if the value is an all-empy value, i.e. `0` in for numbers, all-zero for Arrays (or anything `Uint8Array`), `false` is non-zero
- `.isEmpty` - `true` if the value is an all-empty value, i.e. `0` in for numbers, all-zero for Arrays (or anything `Uint8Array`), `false` is non-zero
- `.hash` - a `Hash` (once again with all the methods above) that is a `blake2-256` representation of the contained value
## Comparing types
@@ -63,7 +63,7 @@ As a real-world example, when an extrinsic is applied, the `Phase` enum has one
An `Option<Type>` attempts to mimic the Rust approach of having `None` and `Some` available. This means the following getters & methods are available on an `Option` -
- `.isNone` - is `true` if no underlying values is warpped, effectively the same as `.isEmpty`
- `.isNone` - is `true` if no underlying values is wrapped, effectively the same as `.isEmpty`
- `.isSome` - this is `true` is a value is wrapped, i.e. if a `Option<u32>` has an actual underlying `u32`
- `.unwrap()` - when `isSome`, this will return the wrapped value, i.e. for `Option<u32>`, this would return the `u32`. When the value is `isNone`, this call will throw an exception.
- `.unwrapOr(<default value>)` - this extends `unwrap()`, returning the wrapped value when `isSome` and in the case of `isNone` it will return the `<default value>` passed.
+5 -5
View File
@@ -4,7 +4,7 @@ Circling back to metadata, by default the metadata information (at this point in
Therefore to cater for all types, a mapping in done on the [@polkadot/types library](https://github.com/polkadot-js/api/tree/master/packages/types/src/interfaces) to define each of the types and align with their underlying structures as it maps to a default Polkadot or Substrate chain.
Additionally, the API contains some logic for chain type detection, for instance in the case of Substrate 1.x based chains, it will define `BlockNumber` & `Index` (nonce) as a `u64`, while for current-generation chains, these will be defined as `u32`. Some of the work in maintaining the API for Polkadot/Substrate is the addition of types as they appear and gets used in the Rust codebases.
Additionally, the API contains some logic for chain type detection, for instance in the case of Substrate 1.x based chains, it will define `BlockNumber` & `Index` (nonce) as a `u64`, while for current-generation chains, these will be defined as `u32`. Some of the work in maintaining the API for Polkadot/Substrate is the addition of types as they appear and gets used in the Rust codebase.
There is a the [recommendation](install.md#betas) to use a `@polkadot/api@beta` should you wish to track the master branches of Polkadot or Substrate, since master changes for the addition of new types do not make it into a stable release immediately.
@@ -24,7 +24,7 @@ const api = await ApiPromise.create({
});
```
The above introduces the `types` registry, effectively allowing overrides and the definition of new types. The override above would mean that immediately the API will treat all occurences of `Balance` not as the default, but rather as the defined size.
The above introduces the `types` registry, effectively allowing overrides and the definition of new types. The override above would mean that immediately the API will treat all occurrences of `Balance` not as the default, but rather as the defined size.
## User-defined types
@@ -52,7 +52,7 @@ const api = await ApiPromise.create({
})
```
The example above defines non-primitive types (as found in the specific implementation) as structs. Additionally it also shows the user-defined types can depend on other user-defined types with `Transaction` referencing both `TransactionInput` and `TransactionOutput`. Here you can reference any known types, i.e. in the above we have referenced primitives such as `u32` and `Signature` (itself an alias for `H512`).
The example above defines non-primitive types (as found in the specific implementation) as structures. Additionally it also shows the user-defined types can depend on other user-defined types with `Transaction` referencing both `TransactionInput` and `TransactionOutput`. Here you can reference any known types, i.e. in the above we have referenced primitives such as `u32` and `Signature` (itself an alias for `H512`).
One form of types that appear regularly is enums, these can be defined as follow -
@@ -137,6 +137,6 @@ const api = await ApiPromise.create({
`Balance` would be defined as an `u128` at the end. Effectively based on the flow it is first registered as a `u32`, then overridden as a `u64` and finally overridden once more as a `u128` by the chain types.
## Using with TypeScript
## Extending extrinsics
The API is built with TypeScript (as are all projects in the [polkadot-js organization](https://github.com/polkadot-js/)) and as such allows developers using TS to have access to all the type interfaces defined on the chain, as well as having access to typings on interacting with the `api.*` namespaces. In the next section we will provide an overview of [what is available in terms of types and TypeScript](typescript.md).
On customized chains, it is possible to [extend the format of the extrinsics and extrinsic payload as customized on the chain](extrinsic.extend.md), next up we will look at this advanced use-case.
+9
View File
@@ -35,6 +35,8 @@ Events are emitted for certain operations on the runtime. The following sections
- **[treasury](#treasury)**
- **[utility](#utility)**
___
@@ -287,3 +289,10 @@ ___
▸ **Spending**(`Balance`)
- **summary**: We have ended a spend period and will now allocate funds.
___
### utility
▸ **BatchExecuted**(`Vec<DispatchResult>`)
+15 -2
View File
@@ -37,6 +37,8 @@ The following sections contain Extrinsics methods are part of the default Substr
- **[treasury](#treasury)**
- **[utility](#utility)**
___
@@ -161,7 +163,7 @@ ___
▸ **presentWinner**(candidate: `Address`, total: `Compact<BalanceOf>`, index: `Compact<VoteIndex>`)
- **summary**: Claim that `candidate` is one of the top `carry_count + desired_seats` candidates. Only works iff the presentation period is active. `candidate` should have at least collected some non-zero `total` votes and `origin` must have enough funds to pay for a potential slash. # <weight> - O(voters) compute. - One DB change. # </weight>
▸ **proxySetApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `BalanceOf`)
▸ **proxySetApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `Compact<BalanceOf>`)
- **summary**: Set candidate approvals from a proxy. Approval slots stay valid as long as candidates in those slots are registered. # <weight> - Same as `set_approvals` with one additional storage read. # </weight>
▸ **reapInactiveVoter**(reporter_index: `Compact<u32>`, who: `Address`, who_index: `Compact<u32>`, assumed_vote_index: `Compact<VoteIndex>`)
@@ -173,7 +175,7 @@ ___
▸ **retractVoter**(index: `Compact<u32>`)
- **summary**: Remove a voter. All votes are cancelled and the voter deposit is returned. The index must be provided as explained in [`voter_at`] function. Also removes the lock on the balance of the voter. See [`do_set_approvals()`]. # <weight> - O(1). - Two fewer DB entries, one DB change. # </weight>
▸ **setApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `BalanceOf`)
▸ **setApprovals**(votes: `Vec<bool>`, index: `Compact<VoteIndex>`, hint: `SetIndex`, value: `Compact<BalanceOf>`)
- **summary**: Set candidate approvals. Approval slots stay valid as long as candidates in those slots are registered. Locks `value` from the balance of `origin` indefinitely. Only [`retract_voter`] or [`reap_inactive_voter`] can unlock the balance. `hint` argument is interpreted differently based on: - if `origin` is setting approvals for the first time: The index will be checked for being a valid _hole_ in the voter list. - if the hint is correctly pointing to a hole, no fee is deducted from `origin`. - Otherwise, the call will succeed but the index is ignored and simply a push to the last chunk with free space happens. If the new push causes a new chunk to be created, a fee indicated by [`VotingFee`] is deducted. - if `origin` is already a voter: the index __must__ be valid and point to the correct position of the `origin` in the current voters list. Note that any trailing `false` votes in `votes` is ignored; In approval voting, not voting for a candidate and voting false, are equal. # <weight> - O(1). - Two extra DB entries, one DB change. - Argument `votes` is limited in length to number of candidates. # </weight>
▸ **setDesiredSeats**(count: `Compact<u32>`)
@@ -285,6 +287,9 @@ ___
▸ **fillBlock**()
- **summary**: A big dispatch that will disallow any other transaction to be included.
▸ **killPrefix**(prefix: `Key`)
- **summary**: Kill all storage items with a key that starts with the given prefix.
▸ **killStorage**(keys: `Vec<Key>`)
- **summary**: Kill some items from storage.
@@ -355,3 +360,11 @@ ___
▸ **rejectProposal**(proposal_id: `Compact<ProposalIndex>`)
- **summary**: Reject a proposed spend. The original deposit will be slashed. # <weight> - O(1). - Limited storage reads. - One DB clear. # </weight>
___
### utility
▸ **batch**(calls: `Vec<Call>`)
- **summary**: Send a batch of dispatch calls (only root).
+1 -1
View File
@@ -9,5 +9,5 @@
"packages": [
"packages/*"
],
"version": "0.93.1"
"version": "0.96.1"
}
+9 -12
View File
@@ -1,5 +1,5 @@
{
"version": "0.93.1",
"version": "0.96.1",
"private": true,
"engines": {
"yarn": "^1.10.1"
@@ -9,15 +9,13 @@
],
"resolutions": {
"babel-core": "^7.0.0-bridge.0",
"typescript": "^3.6.3"
"typescript": "^3.7.2"
},
"scripts": {
"build": "yarn build:interfaces && polkadot-dev-build-ts && yarn run build:methodsdoc && polkadot-dev-build-docs",
"build:htmldoc": "yarn clean && typedoc --theme default --out docs/html",
"build": "yarn build:interfaces && polkadot-dev-build-ts",
"build:interfaces": "node packages/types/src/scripts/interfacesTsWrapper.js",
"build:methodsdoc": "node packages/types/src/scripts/MetadataMdWrapper.js",
"docs": "node packages/types/src/scripts/MetadataMdWrapper.js && polkadot-dev-build-docs",
"chain:info": "node packages/types/src/scripts/extractChainWrapper.js",
"check": "yarn lint",
"lint": "eslint --ext .js,.jsx,.ts,.tsx . && tsc --noEmit --pretty",
"clean": "polkadot-dev-clean-build",
"postinstall": "polkadot-dev-yarn-only",
@@ -30,11 +28,10 @@
"test:watch": "jest --coverage --watch"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/register": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@polkadot/dev": "^0.31.1",
"@polkadot/ts": "^0.1.73",
"gh-pages": "^2.1.1"
"@babel/core": "^7.7.0",
"@babel/register": "^7.7.0",
"@babel/runtime": "^7.6.3",
"@polkadot/dev": "^0.32.0-beta.13",
"@polkadot/ts": "^0.1.84"
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@polkadot/api-contract",
"version": "0.93.1",
"version": "0.96.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.2",
"@polkadot/types": "^0.93.1"
"@babel/runtime": "^7.7.1",
"@polkadot/types": "^0.96.1"
}
}
+5 -102
View File
@@ -2,118 +2,21 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABIArg } from './types';
import typesAbi from '../test/abi/types.json';
import erc20Abi from '../test/contracts/Erc20.json';
import incrementerAbi from '../test/contracts/incrementer.json';
import { Abi } from '.';
describe('Abi', (): void => {
describe('types encoding', (): void => {
let abi: Abi;
beforeAll((): void => {
abi = new Abi(typesAbi);
});
function check (method: string, args: ContractABIArg[], type: string | null): void {
const fn = abi.messages[method];
expect(fn.args).toEqual(args);
expect(fn.type).toEqual(type);
}
it('has the primitive method with args & return', (): void => {
check(
'primitive',
[
{ name: 'bool', type: 'bool' },
{ name: 'u32', type: 'u32' }
],
'bool'
);
});
it('has the vector method with args & return', (): void => {
check(
'vector',
[
{ name: 'vecU8', type: 'Vec<u8>' },
{ name: 'vecU32', type: 'Vec<u32>' }
],
'Vec<bool>'
);
});
it('has the vector_fixed method with args & return', (): void => {
check(
'vectorFixed',
[
{ name: 'vecU8Length32', type: '[u8;32]' }
],
'[u32;8]'
);
});
it('has the option method with args & return', (): void => {
check(
'option',
[
{ name: 'optionU32', type: 'Option<u32>' }
],
'Option<bool>'
);
});
it('has the result method with return (empty)', (): void => {
check(
'result',
[],
'()'
);
});
it('allows for nested args', (): void => {
check(
'nested',
[
{ name: 'optionVec', type: 'Option<Vec<u32>>' }
],
'Vec<(u32,u64)>'
);
});
describe('messages', (): void => {
it('fails when invalid args are supplied', (): void => {
expect(
(): Uint8Array => abi.messages.primitive(false)
).toThrow(/Expected 2 arguments to contract messages.primitive, found 1/);
});
it('encodes primitives correctly', (): void => {
expect(
abi.messages.primitive(true, 0x12345678)
).toEqual(new Uint8Array([
9 << 2, // total length (4 + 1 + 4)
0x67, 0x2b, 0, 0, // 11111 -> hex (LE)
1, // true
0x78, 0x56, 0x34, 0x12 // u32
]));
});
});
});
describe('erc20', (): void => {
describe('incrementer', (): void => {
let abi: Abi;
beforeEach((): void => {
abi = new Abi(erc20Abi);
abi = new Abi(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']
);
});
});
+30 -15
View File
@@ -2,30 +2,45 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ContractABI, ContractABIFn, InterfaceAbi, AbiMessages } from './types';
import { AbiConstructors, AbiMessages, ContractABI, ContractABIPre, ContractABIFn, InterfaceAbi } from './types';
import { stringCamelCase } from '@polkadot/util';
import { createMethod } from './method';
import { validateAbi } from './validation';
import ContractRegistry from './ContractRegistry';
export default class ContractAbi implements InterfaceAbi {
export default class ContractAbi extends ContractRegistry implements InterfaceAbi {
public readonly abi: ContractABI;
public readonly deploy: ContractABIFn;
public readonly constructors: AbiConstructors;
public readonly messages: AbiMessages = {};
public readonly messages: AbiMessages;
public constructor (abi: ContractABI) {
validateAbi(abi);
constructor (abi: ContractABIPre) {
super(abi);
[this.abi, this.constructors, this.messages] = this.decodeAbi(abi);
}
this.abi = abi;
this.deploy = createMethod('deploy', abi.deploy);
private decodeAbi (abiPre: ContractABIPre): [ContractABI, ContractABIFn[], AbiMessages] {
this.validateAbi(abiPre);
abi.messages.forEach((method): void => {
const name = stringCamelCase(method.name);
const abi = this.convertAbi(abiPre);
const constructors = abi.contract.constructors.map(
(constructor, index): ContractABIFn => {
return this.createMessage(`constructor ${index}`, constructor);
}
);
this.messages[name] = createMethod(`messages.${name}`, method);
});
const messages: AbiMessages = abi.contract.messages.reduce(
(result: AbiMessages, message): AbiMessages => {
const name = stringCamelCase(message.name);
return {
...result,
[name]: this.createMessage(`messages.${name}`, message)
};
},
{}
);
return [abi, constructors, messages];
}
}
@@ -0,0 +1,219 @@
// 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 { CodecArg, Constructor, 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 { 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';
// 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 (fnname: string, input: ContractABIMessageCommon['selector']): u32 {
if (isNumber(input)) {
return createType('u32', input);
} else if (isHex(input)) {
return createType('u32', hexToU8a(input));
} else if (typeof input === 'string') {
try {
const array = JSON.parse(input);
assert(array.length === 4, `${fnname}: Invalid selector length`);
return createType('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 (args: ContractABIFnArg[], baseDef: Record<string, string>): Constructor {
return createClass(
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
public validateArgs (name: string, args: ContractABIArgBasePre[]): void {
assert(Array.isArray(args), `Expected 'args' to exist on ${name}`);
args.forEach((arg): void => {
const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`);
assert(isNumber(arg.name) && isString(this.stringAt(arg.name)), `${name} args should have valid name `);
assert(isNumber(arg.type.ty) && isObject(this.typeDefAt(arg.type.ty)), `${name} args should have valid type`);
});
}
public validateConstructors ({ contract: { constructors } }: ContractABIPre): 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`);
this.validateArgs(`constructor ${index}`, constructor.args);
});
}
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.${message.name}`);
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(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.validateMessages(abi);
}
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(message.selector) ? {} : { __selector: 'u32' });
const baseStruct: { [index: string]: any } = { __selector: isUndefined(message.selector) ? undefined : parseSelector(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(
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
mapped[name] = params[index];
return mapped;
}, { ...baseStruct })
).toU8a();
return Compact.addLengthPrefix(u8a);
};
const fn = (encoder as ContractABIFn);
fn.args = args;
fn.isConstant = !(message.mutates || false);
fn.type = message.returnType || null;
return fn;
}
public convertAbi ({ contract, storage }: ContractABIPre): ContractABI {
return {
contract: this.convertContract(contract),
storage: this.convertStorage(storage)
};
}
public convertArgs (args: ContractABIArgBasePre[]): any[] {
return args.map(({ name, type, ...arg }) => ({ ...arg, name: this.stringAt(name), type: this.convertType(type) }));
}
public convertType ({ ty, display_name: displayNameIndices }: ContractABITypePre): TypeDef {
const displayName = this.stringsAt(displayNameIndices).join('::');
return this.typeDefAt(ty, { displayName });
}
public convertContract ({ constructors, messages, name, events, ...contract }: ContractABIContractPre): ContractABIContract {
return {
constructors: this.convertConstructors(constructors),
messages: messages.map(message => this.convertMessage(message)),
name: this.stringAt(name),
...(events
? { events: events.map(event => this.convertEvent(event)) }
: {}),
...contract
};
}
public convertConstructors (constructors: ContractABIMessagePre[]): ContractABIMessage[] {
return constructors.map(
(constructor: ContractABIMessagePre): ContractABIMessage => {
return this.convertMessage(constructor);
}
);
}
public convertMessage ({ args, name, return_type: returnType, ...message }: ContractABIMessagePre): ContractABIMessage {
return {
...message,
args: this.convertArgs(args),
name: this.stringAt(name),
returnType: returnType ? this.convertType(returnType) : null
};
}
public convertEvent ({ args }: ContractABIEventPre): ContractABIEvent {
return {
args: this.convertArgs(args)
};
}
public convertStorage (storage: ContractABIStoragePre): ContractABIStorage {
return this.convertStorageStruct(storage);
}
public convertStorageLayout (storageLayout: ContractABIStorageLayoutPre): ContractABIStorageLayout {
if ((storageLayout as ContractABIStorageStructPre)['struct.type']) {
return this.convertStorageStruct(storageLayout as ContractABIStorageStructPre);
} else {
return this.convertStorageRange(storageLayout as ContractABIRangePre);
}
}
public convertStorageStruct ({ 'struct.type': structType, 'struct.fields': structFields }: ContractABIStorageStructPre): ContractABIStorageStruct {
return {
'struct.type': this.typeDefAt(structType),
'struct.fields': structFields.map(({ name, layout }) => ({
name: this.stringAt(name),
layout: this.convertStorageLayout(layout)
}))
};
}
public convertStorageRange ({ 'range.elem_type': type, ...range }: ContractABIRangePre): ContractABIRange {
return {
...range,
'range.elem_type': this.typeDefAt(type)
};
}
}
@@ -0,0 +1,33 @@
// Copyright 2017-2019 @polkadot/types 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 fs from 'fs';
import path from 'path';
import MetaRegistry from './MetaRegistry';
import erc20Abi from '../test/contracts/Erc20.json';
import sharedVecAbi from '../test/contracts/SharedVecV2.json';
describe('MetaRegistry', (): void => {
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);
});
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;
});
expect(true).toBe(true);
});
});
});
+348
View File
@@ -0,0 +1,348 @@
// 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 { 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 { assert } from '@polkadot/util';
import { displayType, withTypeString } from '@polkadot/types';
const builtinMap: [(id: any) => boolean, MetaTypeInfo][] = [
[(id: any): boolean => typeof id === 'string', MetaTypeInfo.BuiltinPlain],
[(id: any): boolean => Array.isArray(id), MetaTypeInfo.BuiltinTuple],
[(id: any): boolean => !!(id['array.type']), MetaTypeInfo.BuiltinVecFixed],
[(id: any): boolean => !!(id['slice.type']), MetaTypeInfo.BuiltinVec]
];
const typeMap: [string, MetaTypeInfo][] = [
['enum.variants', MetaTypeInfo.Enum],
['clike_enum.variants', MetaTypeInfo.ClikeEnum],
['struct.fields', MetaTypeInfo.Struct],
['tuple_struct.types', MetaTypeInfo.TupleStruct]
];
function detectedType ({ def, id }: MetaType): MetaTypeInfo {
assert(!(def as MetaTypeDefUnion)['union.fields'], 'Invalid union type definition found');
const lookup = def === 'builtin'
? builtinMap.find(([test]): boolean => test(id))
: typeMap.find(([test]): boolean => !!(def as any)[test]);
return lookup
? lookup[1]
: MetaTypeInfo.Null;
}
class MetadataRegistryLookup {
protected _strings: string[] = [];
protected _types: MetaType[] = [];
public typeDefs: TypeDef[] = [];
constructor ({ registry: { strings, types } }: MetaRegistryJson) {
this._strings = strings;
this._types = types;
}
protected hasItemAt (index: number, variant: MetaRegistryItem): boolean {
switch (variant) {
case MetaRegistryItem.String:
return this._strings && !!this._strings[index - 1];
case MetaRegistryItem.Type:
return this._types && !!this._types[index - 1];
case MetaRegistryItem.TypeDef:
return this.typeDefs && !!this.typeDefs[index - 1];
}
}
protected itemAt (index: number, variant: MetaRegistryItem): any {
assert(this.hasItemAt(index, variant), `MetaRegistry: Invalid ${variant} index ${index} found in metadata`);
switch (variant) {
case MetaRegistryItem.String:
return this._strings[index - 1];
case MetaRegistryItem.Type:
return this._types[index - 1];
case MetaRegistryItem.TypeDef:
return this.typeDefs[index - 1];
}
}
protected itemsAt (indices: number[], variant: MetaRegistryItem): any[] {
return indices.map((index: number): string => this.itemAt(index, variant));
}
protected stringAt (index: StringIndex): string {
return this.itemAt(index, MetaRegistryItem.String);
}
public stringsAt (indices: StringIndex[]): string[] {
return this.itemsAt(indices, MetaRegistryItem.String);
}
public typeAt (index: TypeIndex): MetaType {
return this.itemAt(index, MetaRegistryItem.Type);
}
public typesAt (indices: TypeIndex[]): MetaType[] {
return this.itemsAt(indices, MetaRegistryItem.Type);
}
public hasTypeDefAt (index: TypeIndex): boolean {
return this.hasItemAt(index, MetaRegistryItem.TypeDef);
}
public typeDefAt (index: TypeIndex, extra: Pick<TypeDef, never> = {}): TypeDef {
return {
...this.itemAt(index, MetaRegistryItem.TypeDef),
...extra
};
}
}
export default class MetaRegistry extends MetadataRegistryLookup {
constructor (json: MetaRegistryJson) {
super(json);
// Generate TypeDefs for each provided registry type
this._types.forEach((_, index: number): void => this.setTypeDefAtIndex(index + 1));
}
public setTypeDefAtIndex (typeIndex: TypeIndex): void {
this.typeDefs[typeIndex - 1] = this.typeDefFromMetaType(this.typeAt(typeIndex), typeIndex);
}
private typeDefIdFields ({ id }: MetaType): Pick<TypeDef, never> {
const { 'custom.name': nameIndex, 'custom.namespace': namespaceIndices, 'custom.params': paramsIndices } = id as MetaTypeIdCustom;
if (!nameIndex) {
return {};
}
return {
name: this.stringAt(nameIndex),
...(namespaceIndices && namespaceIndices.length
? { namespace: this.stringsAt(namespaceIndices).join('::') }
: {}
),
...(paramsIndices && paramsIndices.length
? { params: this.typesAt(paramsIndices).map((type): TypeDef => this.typeDefFromMetaType(type)) }
: {}
)
};
}
private typeDefDefFields (metaType: MetaType, typeIndex?: TypeIndex): Pick<TypeDef, never> {
let typeDef;
switch (detectedType(metaType)) {
case MetaTypeInfo.BuiltinPlain:
typeDef = this.typeDefForBuiltinPlain(metaType.id as string);
break;
case MetaTypeInfo.BuiltinTuple:
typeDef = this.typeDefForBuiltinTuple(metaType.id as TypeIndex[]);
break;
case MetaTypeInfo.BuiltinVec:
typeDef = this.typeDefForBuiltinVec(metaType.id as MetaTypeIdVec, typeIndex);
break;
case MetaTypeInfo.BuiltinVecFixed:
typeDef = this.typeDefForBuiltinVecFixed(metaType.id as MetaTypeIdVecFixed, typeIndex);
break;
case MetaTypeInfo.Enum:
typeDef = this.typeDefForEnum(metaType.def as MetaTypeDefEnum, metaType.id as MetaTypeIdCustom, typeIndex);
break;
case MetaTypeInfo.ClikeEnum:
typeDef = this.typeDefForClikeEnum(metaType.def as MetaTypeDefClikeEnum);
break;
case MetaTypeInfo.Struct:
typeDef = this.typeDefForStruct(metaType.def as MetaTypeDefStruct);
break;
case MetaTypeInfo.TupleStruct:
typeDef = this.typeDefForTupleStruct(metaType.def as MetaTypeDefTupleStruct);
break;
case MetaTypeInfo.Null:
default:
throw new Error(`Invalid type detected at index ${typeIndex}`);
}
return typeDef;
}
public typeDefFromMetaType (metaType: MetaType, typeIndex?: TypeIndex): TypeDef {
return withTypeString({
info: TypeDefInfo.Null,
type: '',
...this.typeDefDefFields(metaType, typeIndex),
...this.typeDefIdFields(metaType)
}) as TypeDef;
}
public typeDefFromMetaTypeAt (typeIndex: TypeIndex): TypeDef {
if (!this.hasTypeDefAt(typeIndex)) {
this.setTypeDefAtIndex(typeIndex);
}
return this.typeDefAt(typeIndex);
}
private typeDefForEnumVariant (variant: MetaTypeDefEnumVariant): Pick<TypeDef, any> {
const { 'unit_variant.name': unitNameIndex } = variant as MetaTypeDefEnumVariantUnit;
if (unitNameIndex) {
return {
info: TypeDefInfo.Plain,
name: this.stringAt(unitNameIndex),
type: 'Null'
};
}
const { 'tuple_struct_variant.name': tupleStructVariantNameIndex } = variant as MetaTypeDefEnumVariantTupleStruct;
if (tupleStructVariantNameIndex) {
return this.typeDefForTupleStruct(variant as MetaTypeDefEnumVariantTupleStruct);
}
const { 'struct_variant.name': structVariantNameIndex } = variant as MetaTypeDefEnumVariantStruct;
if (structVariantNameIndex) {
return this.typeDefForStruct(variant as MetaTypeDefEnumVariantStruct);
}
return {
info: TypeDefInfo.Null,
type: 'Null'
};
}
private typeDefForBuiltinPlain (id: string): Pick<TypeDef, never> {
return {
info: TypeDefInfo.Plain,
type: id
};
}
private typeDefForBuiltinTuple (id: TypeIndex[]): Pick<TypeDef, never> {
const sub = id.map((tupleTypeIndex: number): TypeDef => this.typeDefFromMetaTypeAt(tupleTypeIndex));
return {
info: TypeDefInfo.Tuple,
sub
};
}
private typeDefForBuiltinVec (id: MetaTypeIdVec, typeIndex?: TypeIndex): Pick<TypeDef, never> {
const { 'slice.type': vecTypeIndex } = id;
assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`);
const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex));
assert(type && type.length > 0, `MetaRegistry: Invalid builtin Vec type found at index ${typeIndex}`);
return {
info: TypeDefInfo.Vec,
type: `Vec<${type}>`,
sub: this.typeDefFromMetaTypeAt(vecTypeIndex)
};
}
private typeDefForBuiltinVecFixed (id: MetaTypeIdVecFixed, typeIndex?: TypeIndex): Pick<TypeDef, never> {
const { 'array.type': vecTypeIndex, 'array.len': vecLength } = id;
assert(!vecLength || vecLength <= 256, 'MetaRegistry: Only support for [Type; <length>], where length <= 256');
assert(!typeIndex || vecTypeIndex !== typeIndex, `MetaRegistry: self-referencing registry type at index ${typeIndex}`);
const type = displayType(this.typeDefFromMetaTypeAt(vecTypeIndex));
assert(type && type.length > 0, `MetaRegistry: Invalid vector type found at index ${typeIndex}`);
return {
info: TypeDefInfo.VecFixed,
ext: { length: vecLength, type },
type: `[${type};${vecLength}]`,
sub: this.typeDefFromMetaTypeAt(vecTypeIndex)
};
}
private typeDefForEnum (def: MetaTypeDefEnum, id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
const name = id && this.stringAt(id['custom.name']);
switch (name) {
case 'Option':
return this.typeDefForOption(id, typeIndex);
case 'Result':
return this.typeDefForResult(id, typeIndex);
default: {
const sub = def['enum.variants'].map(variant => this.typeDefForEnumVariant(variant));
return {
info: TypeDefInfo.Enum,
sub
};
}
}
}
private typeDefForClikeEnum (def: MetaTypeDefClikeEnum): Pick<TypeDef, never> {
return {
info: TypeDefInfo.Enum,
sub: def['clike_enum.variants'].map(({ name: nameIndex, discriminant }): TypeDef => ({
ext: { discriminant },
info: TypeDefInfo.Plain,
name: this.stringAt(nameIndex),
type: 'Null'
}))
};
}
public typeDefForOption (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
assert(id['custom.params'] && id['custom.params'][0], `Invalid Option type defined at index ${typeIndex}`);
return {
info: TypeDefInfo.Option,
sub: this.typeDefFromMetaTypeAt(id['custom.params']![0])
};
}
public typeDefForResult (id: MetaTypeIdCustom, typeIndex?: TypeIndex): Pick<TypeDef, any> {
assert(id['custom.params'] && id['custom.params'][0] && id['custom.params'][1], `Invalid Result type defined at index ${typeIndex}`);
return {
info: TypeDefInfo.Result,
sub: id['custom.params']!.map((typeIndex): TypeDef => this.typeDefFromMetaTypeAt(typeIndex))
};
}
public typeDefForStruct (def: MetaTypeDefStruct | MetaTypeDefEnumVariantStruct): Pick<TypeDef, any> {
const structFields = (def as MetaTypeDefStruct)['struct.fields'] || (def as MetaTypeDefEnumVariantStruct)['struct_variant.fields'];
const structNameIndex = (def as MetaTypeDefEnumVariantStruct)['struct_variant.name'];
return withTypeString({
info: TypeDefInfo.Struct,
...(structNameIndex
? { name: this.stringAt(structNameIndex) }
: {}
),
sub: structFields.map((field: MetaTypeDefStructField): TypeDef => ({
...this.typeDefFromMetaTypeAt(field.type),
name: this.stringAt(field.name)
}))
});
}
private typeDefForTupleStruct (def: MetaTypeDefTupleStruct | MetaTypeDefEnumVariantTupleStruct): Pick<TypeDef, any> {
const tupleStructTypes = (def as MetaTypeDefTupleStruct)['tuple_struct.types'] || (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.types'];
const tupleStructNameIndex = (def as MetaTypeDefEnumVariantTupleStruct)['tuple_struct_variant.name'];
return withTypeString({
info: TypeDefInfo.Tuple,
...(tupleStructNameIndex
? { name: this.stringAt(tupleStructNameIndex) }
: {}
),
sub: tupleStructTypes.map((fieldIndex: number, index: number): TypeDef => ({
...this.typeDefFromMetaTypeAt(fieldIndex),
index
}))
});
}
}
-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, ContractABI, 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: ContractABI | 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');
}
}
-70
View File
@@ -1,70 +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 { ContractABI } 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 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: ContractABI | Abi, codeHash: string | Hash) {
super(api, abi);
this.codeHash = createType('Hash', codeHash);
}
public deployContract (endowment: number | BN, maxGas: number | BN, ...params: any[]): BlueprintCreate {
const signAndSend = (account: IKeyringPair | string | AccountId | Address): BlueprintCreateResultSubscription => {
return this.apiContracts
.create(endowment, maxGas, this.codeHash, this.abi.deploy(...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 { ContractABI } 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: ContractABI | 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 { ContractABI, 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: ContractABI | Abi, address: string | AccountId | Address) {
super(api, abi);
this.address = createType('Address', address);
Object.entries(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('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('ContractCallRequest', {
origin: account,
dest: this.address.toString(),
value,
gasLimit,
inputData: fn(...params)
})
)
.pipe(
map((result: ContractExecResult): ContractCallOutcome =>
this.createOutcome(result, createType('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(data, message.returnType)
: createType('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('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';
+74
View File
@@ -0,0 +1,74 @@
// 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 { 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>;
constructor (api: ApiObject<ApiType>, abi: ContractABIPre | Abi, decorateMethod: DecorateMethod<ApiType>) {
this.abi = abi instanceof Abi
? abi
: new Abi(abi);
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';
-69
View File
@@ -1,69 +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 { CodecArg, Constructor } from '@polkadot/types/types';
import { ContractABIFn, ContractABIFnArg, ContractABIMethod, ContractABIMethodBase, ContractABITypes } from './types';
import { Compact, createClass } from '@polkadot/types';
import { assert, isString, isUndefined, stringCamelCase } from '@polkadot/util';
export function typeToString (type: ContractABITypes): string {
if (isString(type)) {
return type;
} else if (Array.isArray(type)) {
return `(${type.map((type): string => typeToString(type)).join(',')})`;
} else if (type['Option<T>']) {
return `Option<${typeToString(type['Option<T>'].T)}>`;
} else if (type['Result<T,E>']) {
return '()'; // Result is not supported, but only applicable for returns
} else if (type['Vec<T>']) {
return `Vec<${typeToString(type['Vec<T>'].T)}>`;
} else if (type['[T;n]']) {
return `[${typeToString(type['[T;n]'].T)};${type['[T;n]'].n}]`;
}
throw new Error(`Unknown type specified ${JSON.stringify(type)}`);
}
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] = type;
return base;
}, baseDef)
)
);
}
export function createMethod (name: string, method: Partial<ContractABIMethod> & ContractABIMethodBase): ContractABIFn {
const args: ContractABIFnArg[] = method.args.map(({ name, type }): ContractABIFnArg => ({
name: stringCamelCase(name),
type: typeToString(type)
}));
const Clazz = createArgClass(args, isUndefined(method.selector) ? {} : { __selector: 'u32' });
const baseStruct: { [index: string]: any } = { __selector: method.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(
args.reduce((mapped, { name }, index): Record<string, CodecArg> => {
mapped[name] = params[index];
return mapped;
}, { ...baseStruct })
).toU8a();
return Compact.addLengthPrefix(u8a);
};
const fn = (encoder as ContractABIFn);
fn.args = args;
fn.isConstant = !(method.mutates || false);
fn.type = method.return_type ? typeToString(method.return_type) : null;
return fn;
}
@@ -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';
+154 -39
View File
@@ -2,86 +2,191 @@
// 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 ContractABITypesStruct {
'Option<T>'?: {
T: ContractABITypes;
};
'Result<T,E>'?: {
T: ContractABITypes;
E: ContractABITypes;
};
'Vec<T>'?: {
T: ContractABITypes;
};
'[T;n]'?: {
T: ContractABITypes;
n: number;
};
export interface ContractBase<ApiType extends ApiTypes> {
readonly abi: InterfaceAbi;
readonly api: ApiObject<ApiType>;
readonly decorateMethod: DecorateMethod<ApiType>;
getMessage: (name: string) => ContractMessage;
messages: ContractMessage[];
}
export type ContractABITypes = string | ContractABITypesStruct | (string | ContractABITypesStruct)[];
export interface ContractABITypePre {
ty: TypeIndex;
display_name: StringIndex[];
}
export interface ContractABIArg {
export interface ContractABIArgBasePre {
name: StringIndex;
type: ContractABITypePre;
}
export interface ContractABIArgBase {
name: string;
type: ContractABITypes;
type: TypeDef;
}
export interface ContractABIMethodBase {
args: ContractABIArg[];
export type ContractABIMessageArgPre = ContractABIArgBasePre;
export type ContractABIMessageArg = ContractABIArgBase;
export interface ContractABIMessageBase {
args: ContractABIMessageArg[];
}
export interface ContractABIMethod extends ContractABIMethodBase {
export interface ContractABIMessageBasePre {
args: ContractABIMessageArgPre[];
}
export interface ContractABIMessageCommon {
docs?: ContractABIDocs;
mutates?: boolean;
selector: string | number;
}
export interface ContractABIMessagePre extends ContractABIMessageCommon, ContractABIMessageBasePre {
name: StringIndex;
return_type: ContractABITypePre | null;
}
export interface ContractABIMessage extends ContractABIMessageCommon {
args: ContractABIMessageArg[];
name: string;
selector: number;
return_type: ContractABITypes | null;
returnType: TypeDef | null;
}
export interface ContractABIContractCommon {
docs?: ContractABIDocs;
}
export interface ContractABIContractPre extends ContractABIContractCommon {
constructors: ContractABIMessagePre[];
messages: ContractABIMessagePre[];
name: StringIndex;
events?: ContractABIEventPre[];
docs?: ContractABIDocs;
}
export interface ContractABIContract extends ContractABIContractCommon {
constructors: ContractABIMessage[];
messages: ContractABIMessage[];
name: string;
events?: ContractABIEvent[];
docs?: ContractABIDocs;
}
export interface ContractABIPre extends MetaRegistryJson {
storage: ContractABIStoragePre;
contract: ContractABIContractPre;
}
export interface ContractABI {
deploy: ContractABIMethodBase;
messages: ContractABIMethod[];
name: string;
storage: ContractABIStorage;
contract: ContractABIContract;
}
export interface ContractABIFnArg {
name: string;
type: string;
type: TypeDef;
}
export interface ContractABIMeta {
args: ContractABIFnArg[];
isConstant: boolean;
type: string | null;
type: TypeDef | null;
}
export interface ContractABIFn extends ContractABIMeta {
(...args: CodecArg[]): Uint8Array;
}
export interface ContractABIEventArgBase {
indexed: boolean;
}
export interface ContractABIEventArgPre extends ContractABIArgBasePre, ContractABIEventArgBase {}
export interface ContractABIEventArg extends ContractABIArgBase, ContractABIEventArgBase {}
export type ContractABIDocs = string[];
export interface ContractABIEventPre {
args: ContractABIEventArgPre[];
}
export interface ContractABIEvent {
args: ContractABIEventArg[];
}
export interface ContractABIRangeBase {
// can be number[] (old) or hex (new)
'range.offset': number[] | string;
'range.len': number;
}
export interface ContractABIRangePre extends ContractABIRangeBase {
'range.elem_type': TypeIndex;
}
export interface ContractABIRange extends ContractABIRangeBase {
'range.elem_type': TypeDef;
}
export type ContractABIStorageLayoutPre = ContractABIStorageStructPre | ContractABIRangePre;
export type ContractABIStorageLayout = ContractABIStorageStruct | ContractABIRange;
export interface ContractABIStorageStructFieldPre {
name: StringIndex;
layout: ContractABIStorageLayoutPre;
}
export interface ContractABIStorageStructField {
name: string;
layout: ContractABIStorageLayout;
}
export interface ContractABIStorageStructPre {
'struct.type': TypeIndex;
'struct.fields': ContractABIStorageStructFieldPre[];
}
export interface ContractABIStorageStruct {
'struct.type': TypeDef;
'struct.fields': ContractABIStorageStructField[];
}
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 deploy: 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;
}
@@ -90,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;
}
+21
View File
@@ -0,0 +1,21 @@
// 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, TypeDefInfo, TypeDef } from '@polkadot/types/types';
import { Data, Option, createClass } from '@polkadot/types';
import { createTypeUnsafe } from '@polkadot/types/codec';
export function formatData (data: Data, { info, type }: TypeDef): Codec {
const u8a = data.toU8a();
if (info === TypeDefInfo.Option) {
return new Option(
createClass(type),
createTypeUnsafe(type, [u8a], true)
);
}
return createTypeUnsafe(type, [u8a], true);
}
File diff suppressed because it is too large Load Diff
-50
View File
@@ -1,50 +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 { ContractABI, ContractABIArg } from './types';
import { assert, isNumber, isNull, isString, isObject } from '@polkadot/util';
export function validateArgs (name: string, args: ContractABIArg[]): void {
assert(Array.isArray(args), `Expected 'args' to exist on ${name}`);
args.forEach((arg): void => {
const unknownKeys = Object.keys(arg).filter((key): boolean => !['name', 'type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for ${name}`);
assert(isString(arg.name), `${name} args should have valid name `);
assert(isString(arg.type) || isObject(arg.type), `${name} args should have valid type`);
});
}
export function validateDeploy ({ deploy }: ContractABI): void {
const unknownKeys = Object.keys(deploy).filter((key): boolean => !['args'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI deploy`);
validateArgs('deploy', deploy.args);
}
export function validateMethods ({ messages }: ContractABI): void {
messages.forEach((method): void => {
const unknownKeys = Object.keys(method).filter((key): boolean => !['args', 'mutates', 'name', 'selector', 'return_type'].includes(key));
assert(unknownKeys.length === 0, `Unknown keys ${unknownKeys.join(', ')} found in ABI args for messages.${method.name}`);
assert(isString(method.name), `Expected name for messages.${method.name}`);
assert(isNumber(method.selector), `Expected selector for messages.${method.name}`);
assert(isNull(method.return_type) || isString(method.return_type) || isObject(method.return_type), `Expected return_type for messages.${method.name}`);
validateArgs(`messages.${method.name}`, method.args);
});
}
export function validateAbi (abi: ContractABI): void {
const unknownKeys = Object.keys(abi).filter((key): boolean => !['deploy', 'messages', 'name'].includes(key));
assert(unknownKeys.length === 0, `Unknown fields ${unknownKeys.join(', ')} found in ABI`);
assert(abi.deploy && abi.messages && isString(abi.name), 'ABI should have deploy, messages & name sections');
validateDeploy(abi);
validateMethods(abi);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
[
{
"info": 7,
"type": "{\"value\": {\"cell\": {\"cell\": ([u8;32])}}}",
"name": "Flipper",
"namespace": "flipper::normal",
"sub": [
{
"info": 7,
"type": "{\"cell\": {\"cell\": ([u8;32])}}",
"name": "value",
"namespace": "ink_core::storage::value",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 7,
"type": "{\"cell\": ([u8;32])}",
"name": "cell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 8,
"type": "([u8;32])",
"name": "cell",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
}
]
}
]
}
]
},
{
"info": 7,
"type": "{\"cell\": {\"cell\": ([u8;32])}}",
"name": "Value",
"namespace": "ink_core::storage::value",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 7,
"type": "{\"cell\": ([u8;32])}",
"name": "cell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 8,
"type": "([u8;32])",
"name": "cell",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
}
]
}
]
},
{
"info": 5,
"type": "bool"
},
{
"info": 7,
"type": "{\"cell\": ([u8;32])}",
"name": "SyncCell",
"namespace": "ink_core::storage::cell::sync_cell",
"params": [
{
"info": 5,
"type": "bool"
}
],
"sub": [
{
"info": 8,
"type": "([u8;32])",
"name": "cell",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
}
]
},
{
"info": 8,
"type": "([u8;32])",
"name": "Key",
"namespace": "ink_core::storage::key",
"sub": [
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
},
"index": 0
}
]
},
{
"info": 10,
"type": "[u8;32]",
"ext": {
"length": 32,
"type": ""
},
"sub": {
"info": 5,
"type": "u8"
}
},
{
"info": 5,
"type": "u8"
}
]
@@ -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
@@ -0,0 +1,201 @@
{
"registry": {
"strings": [
"Flipper",
"flipper",
"normal",
"value",
"Value",
"ink_core",
"storage",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"flip",
"get"
],
"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": "bool",
"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"
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 8,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 3
}
}
]
}
}
]
},
"contract": {
"name": 1,
"deploy": {
"args": [],
"docs": [
"Initializes our state to `false` upon deploying our smart contract."
]
},
"messages": [
{
"name": 13,
"selector": 970692492,
"mutates": true,
"args": [],
"return_type": null,
"docs": [
"Flips the current state of our smart contract."
]
},
{
"name": 14,
"selector": 4266279973,
"mutates": false,
"args": [],
"return_type": 3,
"docs": [
"Returns the current state."
]
}
],
"events": [],
"docs": []
}
}
@@ -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,935 @@
{
"registry": {
"strings": [
"SharedVec",
"shared_vec",
"normal",
"mutators",
"HashMap",
"ink_core",
"storage",
"collections",
"hash_map",
"impls",
"AccountId",
"env",
"srml",
"types",
"Access",
"begin",
"Option",
"None",
"Some",
"end",
"len",
"Value",
"value",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"entries",
"SyncChunk",
"chunk",
"sync_chunk",
"Entry",
"Occupied",
"OccupiedEntry",
"val",
"Removed",
"cells_key",
"vec",
"Vec",
"cells",
"on_deploy",
"push",
"i32",
"Result",
"Ok",
"Err",
"register",
"mutator",
"set",
"at",
"u32",
"to",
"get",
"Mutate",
"Push",
"Register"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
3
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 4,
"type": 2
},
{
"name": 39,
"type": 15
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8,
9,
10
],
"custom.params": [
3,
6
]
},
"def": {
"struct.fields": [
{
"name": 21,
"type": 9
},
{
"name": 29,
"type": 12
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
12,
13,
14
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
4
]
}
},
{
"id": {
"array.len": 32,
"array.type": 5
},
"def": "builtin"
},
{
"id": "u8",
"def": "builtin"
},
{
"id": {
"custom.name": 15,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 16,
"type": 7
},
{
"name": 20,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 17,
"custom.namespace": [],
"custom.params": [
8
]
},
"def": {
"enum.variants": [
{
"unit_variant.name": 18
},
{
"tuple_struct_variant.name": 19,
"tuple_struct_variant.types": [
8
]
}
]
}
},
{
"id": "u32",
"def": "builtin"
},
{
"id": {
"custom.name": 22,
"custom.namespace": [
6,
7,
23
],
"custom.params": [
8
]
},
"def": {
"struct.fields": [
{
"name": 24,
"type": 10
}
]
}
},
{
"id": {
"custom.name": 25,
"custom.namespace": [
6,
7,
24,
26
],
"custom.params": [
8
]
},
"def": {
"struct.fields": [
{
"name": 24,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 27,
"custom.namespace": [
6,
7,
28
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
4
]
}
},
{
"id": {
"custom.name": 30,
"custom.namespace": [
6,
7,
31,
32,
31
],
"custom.params": [
13
]
},
"def": {
"struct.fields": [
{
"name": 38,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 33,
"custom.namespace": [
6,
7,
8,
9,
10
],
"custom.params": [
3,
6
]
},
"def": {
"enum.variants": [
{
"tuple_struct_variant.name": 34,
"tuple_struct_variant.types": [
14
]
},
{
"unit_variant.name": 37
}
]
}
},
{
"id": {
"custom.name": 35,
"custom.namespace": [
6,
7,
8,
9,
10
],
"custom.params": [
3,
6
]
},
"def": {
"struct.fields": [
{
"name": 28,
"type": 3
},
{
"name": 36,
"type": 6
}
]
}
},
{
"id": {
"custom.name": 40,
"custom.namespace": [
6,
7,
8,
39,
10
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 21,
"type": 9
},
{
"name": 41,
"type": 17
}
]
}
},
{
"id": "i32",
"def": "builtin"
},
{
"id": {
"custom.name": 30,
"custom.namespace": [
6,
7,
31,
32,
31
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 38,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 45,
"custom.namespace": [],
"custom.params": [
19,
8
]
},
"def": {
"enum.variants": [
{
"tuple_struct_variant.name": 46,
"tuple_struct_variant.types": [
19
]
},
{
"tuple_struct_variant.name": 47,
"tuple_struct_variant.types": [
8
]
}
]
}
},
{
"id": [],
"def": "builtin"
},
{
"id": {
"custom.name": 45,
"custom.namespace": [],
"custom.params": [
16,
8
]
},
"def": {
"enum.variants": [
{
"tuple_struct_variant.name": 46,
"tuple_struct_variant.types": [
16
]
},
{
"tuple_struct_variant.name": 47,
"tuple_struct_variant.types": [
8
]
}
]
}
},
{
"id": {
"custom.name": 17,
"custom.namespace": [],
"custom.params": [
16
]
},
"def": {
"enum.variants": [
{
"unit_variant.name": 18
},
{
"tuple_struct_variant.name": 19,
"tuple_struct_variant.types": [
16
]
}
]
}
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 21,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 24,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 8
}
}
]
}
},
{
"name": 29,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1
],
"range.len": 4294967295,
"range.elem_type": 13
}
}
]
}
},
{
"name": 39,
"layout": {
"struct.type": 15,
"struct.fields": [
{
"name": 21,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 24,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 8
}
}
]
}
},
{
"name": 41,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
1
],
"range.len": 4294967295,
"range.elem_type": 16
}
}
]
}
}
]
},
"contract": {
"name": 1,
"constructors": [
{
"name": 42,
"selector": 0,
"args": [],
"docs": [
"Initializes the value to the initial value."
]
}
],
"messages": [
{
"name": 43,
"selector": 865577567,
"mutates": true,
"args": [
{
"name": 23,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"return_type": {
"ty": 18,
"display_name": [
45
]
},
"docs": [
"Pushes a new value to the shared vector.",
"",
"# Errors",
"",
"- If the caller does not have unlimited access rights."
]
},
{
"name": 48,
"selector": 572030971,
"mutates": true,
"args": [
{
"name": 49,
"type": {
"ty": 3,
"display_name": [
11
]
}
},
{
"name": 16,
"type": {
"ty": 7,
"display_name": [
17
]
}
},
{
"name": 20,
"type": {
"ty": 7,
"display_name": [
17
]
}
}
],
"return_type": {
"ty": 18,
"display_name": [
45
]
},
"docs": [
"Registers a new user with the given access rights.",
"",
"Can also be used to change access rights of an already existing user.",
"",
"# Errors",
"",
"- If the caller does not have unlimited access rights."
]
},
{
"name": 50,
"selector": 2028185770,
"mutates": true,
"args": [
{
"name": 51,
"type": {
"ty": 8,
"display_name": [
52
]
}
},
{
"name": 53,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"return_type": {
"ty": 20,
"display_name": [
45
]
},
"docs": [
"Sets the value at the given position to the given value.",
"",
"Returns the previous value.",
"",
"# Errors",
"",
"- If the given position is out of bounds.",
"- If the caller does not have the required access rights."
]
},
{
"name": 54,
"selector": 4266279973,
"mutates": false,
"args": [
{
"name": 51,
"type": {
"ty": 8,
"display_name": [
52
]
}
}
],
"return_type": {
"ty": 21,
"display_name": [
17
]
},
"docs": [
"Returns the value of the shared vector at the given position",
"or `None` if the access is out of bounds."
]
},
{
"name": 21,
"selector": 1403873684,
"mutates": false,
"args": [],
"return_type": {
"ty": 8,
"display_name": [
52
]
},
"docs": [
"Returns the length of the shared vector."
]
}
],
"events": [
{
"name": 55,
"args": [
{
"name": 51,
"indexed": false,
"type": {
"ty": 8,
"display_name": [
52
]
}
},
{
"name": 23,
"indexed": false,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"docs": [
"Fires whenever a mutator changes the vector."
]
},
{
"name": 56,
"args": [
{
"name": 49,
"indexed": false,
"type": {
"ty": 3,
"display_name": [
11
]
}
},
{
"name": 23,
"indexed": false,
"type": {
"ty": 16,
"display_name": [
44
]
}
}
],
"docs": [
"Fires whenever a mutator pushes the vector successfully."
]
},
{
"name": 57,
"args": [
{
"name": 49,
"indexed": false,
"type": {
"ty": 3,
"display_name": [
11
]
}
},
{
"name": 16,
"indexed": false,
"type": {
"ty": 7,
"display_name": [
17
]
}
},
{
"name": 20,
"indexed": false,
"type": {
"ty": 7,
"display_name": [
17
]
}
}
],
"docs": [
"Fires whenever a new mutator is registered",
"or when a mutators access rights are changed."
]
}
],
"docs": []
}
}
@@ -0,0 +1,697 @@
{
"registry": {
"strings": [
"RustStructures",
"structures",
"normal",
"my_tuple_struct",
"Value",
"ink_core",
"storage",
"value",
"TupleStruct",
"cell",
"SyncCell",
"sync_cell",
"Key",
"key",
"my_struct",
"Struct",
"first",
"seconds",
"my_clike_enum",
"ClikeEnum",
"FirstVariant",
"SecondVariant",
"ThirdVariant",
"my_enum",
"RustEnum",
"NoData",
"TupleVariant",
"StructVariant",
"second",
"my_union",
"Union"
],
"types": [
{
"id": {
"custom.name": 1,
"custom.namespace": [
2,
3
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 4,
"type": 2
},
{
"name": 15,
"type": 9
},
{
"name": 19,
"type": 12
},
{
"name": 24,
"type": 15
},
{
"name": 30,
"type": 18
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 6
}
]
}
},
{
"id": {
"custom.name": 9,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
4,
5
]
}
},
{
"id": "u8",
"def": "builtin"
},
{
"id": "u16",
"def": "builtin"
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
3
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 13,
"custom.namespace": [
6,
7,
14
],
"custom.params": []
},
"def": {
"tuple_struct.types": [
8
]
}
},
{
"id": {
"array.len": 32,
"array.type": 4
},
"def": "builtin"
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
10
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 11
}
]
}
},
{
"id": {
"custom.name": 16,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"struct.fields": [
{
"name": 17,
"type": 4
},
{
"name": 18,
"type": 5
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
10
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
13
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 14
}
]
}
},
{
"id": {
"custom.name": 20,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"clike_enum.variants": [
{
"name": 21,
"discriminant": 0
},
{
"name": 22,
"discriminant": 1
},
{
"name": 23,
"discriminant": 42
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
13
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 17
}
]
}
},
{
"id": {
"custom.name": 25,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"enum.variants": [
{
"unit_variant.name": 26
},
{
"tuple_struct_variant.name": 27,
"tuple_struct_variant.types": [
4,
5
]
},
{
"struct_variant.name": 28,
"struct_variant.fields": [
{
"name": 17,
"type": 4
},
{
"name": 29,
"type": 5
}
]
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
16
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
},
{
"id": {
"custom.name": 5,
"custom.namespace": [
6,
7,
8
],
"custom.params": [
19
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 20
}
]
}
},
{
"id": {
"custom.name": 31,
"custom.namespace": [
2
],
"custom.params": []
},
"def": {
"union.fields": [
{
"name": 17,
"type": 4
},
{
"name": 29,
"type": 5
}
]
}
},
{
"id": {
"custom.name": 11,
"custom.namespace": [
6,
7,
10,
12
],
"custom.params": [
19
]
},
"def": {
"struct.fields": [
{
"name": 10,
"type": 7
}
]
}
}
]
},
"storage": {
"struct.type": 1,
"struct.fields": [
{
"name": 4,
"layout": {
"struct.type": 2,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"range.len": 1,
"range.elem_type": 3
}
}
]
}
},
{
"name": 15,
"layout": {
"struct.type": 9,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1
],
"range.len": 1,
"range.elem_type": 10
}
}
]
}
},
{
"name": 19,
"layout": {
"struct.type": 12,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
"range.len": 1,
"range.elem_type": 13
}
}
]
}
},
{
"name": 24,
"layout": {
"struct.type": 15,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
3
],
"range.len": 1,
"range.elem_type": 16
}
}
]
}
},
{
"name": 30,
"layout": {
"struct.type": 18,
"struct.fields": [
{
"name": 10,
"layout": {
"range.offset": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
4
],
"range.len": 1,
"range.elem_type": 19
}
}
]
}
}
]
},
"contract": {
"name": 1,
"deploy": {
"args": [],
"docs": []
},
"messages": [],
"events": [],
"docs": []
}
}
@@ -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.93.1",
"version": "0.96.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.2",
"@polkadot/api": "^0.93.1",
"@polkadot/types": "^0.93.1"
"@babel/runtime": "^7.7.1",
"@polkadot/api": "^0.96.1",
"@polkadot/types": "^0.96.1"
},
"devDependencies": {
"@polkadot/keyring": "^1.5.1"
"@polkadot/keyring": "^1.7.0-beta.5"
}
}
+30 -32
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 { 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 { drr } 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('AccountId', decoded);
return api.derive.accounts.idToIndex(accountId).pipe(
map((accountIndex): AccountIdAndIndex => [accountId, accountIndex] as AccountIdAndIndex)
);
}
const accountIndex = createType('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 (address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> =>
retrieve(api, address).pipe(drr());
}
+9 -10
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 { drr } from '../util';
/**
* @name idToIndex
@@ -27,12 +27,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()
);
api.derive.accounts.indexes().pipe(
startWith({}),
map((indexes: AccountIndexes): AccountIndex | undefined =>
(indexes || {})[accountId.toString()]
),
drr()
);
}
@@ -6,3 +6,4 @@ export * from './idAndIndex';
export * from './idToIndex';
export * from './indexToId';
export * from './indexes';
export * from './info';
+10 -10
View File
@@ -10,7 +10,7 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { ENUMSET_SIZE } from '@polkadot/types/primitive/Generic/AccountIndex';
import { createType, ClassOf, Vec } from '@polkadot/types';
import { drr } from '../util/drr';
import { drr } from '../util';
/**
* @name indexToId
@@ -26,19 +26,19 @@ import { drr } from '../util/drr';
* ```
*/
export function indexToId (api: ApiInterfaceRx): (accountIndex: AccountIndex | string) => Observable<AccountId | undefined> {
const querySection = api.query.indices || api.query.balances;
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);
return (querySection.enumSet<Vec<AccountId>>(accountIndex.div(ENUMSET_SIZE)))
.pipe(
startWith([]),
map((accounts): AccountId | undefined =>
(accounts || [])[accountIndex.mod(ENUMSET_SIZE).toNumber()]
),
drr()
);
return querySection.enumSet<Vec<AccountId>>(accountIndex.div(ENUMSET_SIZE)).pipe(
startWith([]),
map((accounts): AccountId | undefined =>
(accounts || [])[accountIndex.mod(ENUMSET_SIZE).toNumber()]
),
drr()
);
};
}
+24 -27
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 { drr } from '../util/drr';
export type AccountIndexes = Record<string, AccountIndex>;
import { drr } from '../util';
const enumsetSize = ENUMSET_SIZE.toNumber();
@@ -32,29 +31,27 @@ 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 (): 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<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;
result[accountId.toString()] = createType('AccountIndex', index);
});
result[accountId.toString()] = createType('AccountIndex', index);
});
return result;
}, {} as unknown as AccountIndexes)),
drr()
);
};
return result;
}, {} as AccountIndexes)),
drr()
);
}
+49
View File
@@ -0,0 +1,49 @@
// 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 { Codec } 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 { drr } from '../util';
function retrieveNick (api: ApiInterfaceRx, accountId?: AccountId): Observable<string | undefined> {
return accountId && api.query.nicks
? api.query.nicks
.nameOf<Option<[Bytes, Balance] & Codec>>(accountId)
.pipe(
map((nameOf): string | undefined =>
nameOf?.isSome
? u8aToString(nameOf.unwrap()[0]).substr(0, (api.consts.nicks.maxLength as u32).toNumber())
: undefined
)
)
: of(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 (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
})),
drr()
);
}
+44 -42
View File
@@ -3,46 +3,39 @@
// 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';
import { map, switchMap } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { ClassOf, Option, createType } from '@polkadot/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 { drr } from '../util';
type Result = [AccountId | undefined, BlockNumber | undefined, [Balance?, Balance?, BalanceLock[]?, Option<VestingSchedule>?, Index?]];
type ResultBalance = [Balance, Balance, BalanceLock[], Option<VestingSchedule>];
type Result = [AccountId, BlockNumber, ResultBalance, Index];
function calcBalances ([accountId = createType('AccountId'), bestNumber = createType('Balance'), [freeBalance = createType('Balance'), reservedBalance = createType('Balance'), locks = [], vesting = new Option<VestingSchedule>(ClassOf('VestingSchedule'), null), accountNonce = createType('Balance')]]: Result): DerivedBalances {
function calcBalances ([accountId, bestNumber, [freeBalance, reservedBalance, locks, vesting], accountNonce]: Result): DerivedBalances {
let lockedBalance = createType('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]
? bnMax(...totals.map(({ amount }): Balance => amount)) as Balance
: createType('Balance');
if (lockedBreakdown.length) {
lockedBalance = createType('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: BN = perBlock.mul(bestNumber);
const vestedBalance: BN = vestedNow.gt(offset)
? freeBalance
: freeBalance.sub(offset).add(vestedNow);
// 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: BN = bnMax(createType('Balance'), vestedBalance.sub(lockedBalance));
const { offset: vestingTotal, perBlock } = vesting.unwrapOr(createType('VestingSchedule'));
const vestedNow = createType('Balance', perBlock.mul(bestNumber));
const vestedBalance = createType('Balance', vestedNow.gt(vestingTotal) ? new BN(0) : bnMax(new BN(0), freeBalance.sub(vestingTotal).add(vestedNow)));
const availableBalance = createType('Balance', bnMax(new BN(0), (vestedBalance.gtn(0) ? vestedBalance : freeBalance).sub(lockedBalance)));
return {
accountId,
@@ -50,49 +43,58 @@ function calcBalances ([accountId = createType('AccountId'), bestNumber = create
availableBalance,
freeBalance,
lockedBalance,
lockedBreakdown,
reservedBalance,
vestedBalance,
votingBalance: freeBalance.add(reservedBalance)
} as unknown as DerivedBalances;
vestingTotal,
votingBalance: createType('Balance', freeBalance.add(reservedBalance))
};
}
function queryBalances (api: ApiInterfaceRx, accountId: AccountId): Observable<ResultBalance> {
return api.queryMulti<[Balance, Balance, Vec<BalanceLock>, Option<VestingSchedule>]>([
[api.query.balances.freeBalance, accountId],
[api.query.balances.reservedBalance, accountId],
[api.query.balances.locks, accountId],
[api.query.balances.vesting, accountId]
]);
}
/**
* @name all
* @param {( AccountIndex | AccountId | Address | string )} address - An accounts Id in different formats.
* @returns An object containing the combined results of the storage queries for
* all relevant fees as declared in the substrate chain spec.
* @returns An object containing the results of various balance queries
* @example
* <BR>
*
* ```javascript
* const ALICE = 'F7Hs';
*
* api.derive.balances.all(ALICE, ([accountId, lockedBalance]) => {
* api.derive.balances.all(ALICE, ({ accountId, lockedBalance }) => {
* console.log(`The account ${accountId} has a locked balance ${lockedBalance} units.`);
* });
* ```
*/
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 (address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> =>
api.derive.accounts.info(address).pipe(
switchMap(({ accountId }): Observable<Result> =>
(accountId
? combineLatest([
of(accountId),
bestNumber(api)(),
api.queryMulti([
[api.query.balances.freeBalance, accountId],
[api.query.balances.reservedBalance, accountId],
[api.query.balances.locks, accountId],
[api.query.balances.vesting, accountId],
[api.query.system.accountNonce, accountId]
])
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
// ? api.rpc.account.nextIndex(accountId)
// // otherwise we end up with this: type 'Codec | Index' is not assignable to type 'Index'.
// : api.query.system.accountNonce<Index>(accountId)
api.query.system.accountNonce<Index>(accountId)
])
: of([undefined, undefined, [undefined, undefined, undefined, undefined, undefined]])
) as Observable<Result>
: of([createType('AccountId'), createType('BlockNumber'), [createType('Balance'), createType('Balance'), createType('Vec<BalanceLock>'), createType('Option<VestingSchedule>', null)], createType('Index')])
)
),
map(calcBalances),
drr()
);
};
}
+26 -25
View File
@@ -3,37 +3,39 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { ApiInterfaceRx } from '@polkadot/api/types';
import { Balance } from '@polkadot/types/interfaces';
import { DerivedFees } from '../types';
import BN from 'bn.js';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { drr } from '../util/drr';
import { drr } from '../util';
type Result = [BN, BN, BN, BN, BN];
type Result = [Balance, Balance, Balance, Balance, Balance];
function queryV2 (api: ApiInterfaceRx): Observable<Result> {
const paymentBase = api.consts.transactionPayment || api.consts.balances;
function querySubtrateV2 (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,
api.consts.balances.existentialDeposit,
api.consts.balances.transactionBaseFee,
api.consts.balances.transactionByteFee,
api.consts.balances.transferFee
]) as any as Observable<Result>;
api.consts.balances.creationFee as Balance,
api.consts.balances.existentialDeposit as Balance,
api.consts.balances.transferFee as Balance,
paymentBase.transactionBaseFee as Balance,
paymentBase.transactionByteFee as Balance
]);
}
function querySubtrateV1 (api: ApiInterfaceRx): Observable<Result> {
return api.queryMulti([
function queryV1 (api: ApiInterfaceRx): Observable<Result> {
return api.queryMulti<Result>([
// Support older versions and get values from storage
api.query.balances.creationFee,
api.query.balances.existentialDeposit,
api.query.balances.transferFee,
api.query.balances.transactionBaseFee,
api.query.balances.transactionByteFee,
api.query.balances.transferFee
]) as any as Observable<Result>;
api.query.balances.transactionByteFee
]);
}
/**
@@ -44,26 +46,25 @@ function querySubtrateV1 (api: ApiInterfaceRx): Observable<Result> {
* <BR>
*
* ```javascript
* api.derive.balances.fees(([creationFee, transferFee]) => {
* api.derive.balances.fees(({ creationFee, transferFee }) => {
* console.log(`The fee for creating a new account on this chain is ${creationFee} units. The fee required for making a transfer is ${transferFee} units.`);
* });
* ```
*/
export function fees (api: ApiInterfaceRx): () => Observable<DerivedFees> {
return (): Observable<DerivedFees> => {
return (
api.consts.balances
? querySubtrateV2(api)
: querySubtrateV1(api)
).pipe(
map(([creationFee, existentialDeposit, transactionBaseFee, transactionByteFee, transferFee]): DerivedFees => ({
const query = api.consts.balances
? queryV2
: queryV1;
return (): Observable<DerivedFees> =>
query(api).pipe(
map(([creationFee, existentialDeposit, transferFee, transactionBaseFee, transactionByteFee]): DerivedFees => ({
creationFee,
existentialDeposit,
transactionBaseFee,
transactionByteFee,
transferFee
} as unknown as DerivedFees)),
})),
drr()
);
};
}
@@ -8,17 +8,18 @@ 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 { drr } from '../util';
export function votingBalances (api: ApiInterfaceRx): (addresses?: (AccountId | AccountIndex | Address | string)[]) => Observable<DerivedBalances[]> {
return (addresses?: (AccountId | AccountIndex | Address | string)[]): Observable<DerivedBalances[]> => {
return (
return (addresses?: (AccountId | AccountIndex | Address | string)[]): Observable<DerivedBalances[]> =>
(
!addresses || !addresses.length
? of([] as DerivedBalances[])
: combineLatest(addresses.map(all(api)))
: combineLatest(
addresses.map((accountId): Observable<DerivedBalances> =>
api.derive.balances.all(accountId))
)
).pipe(
drr()
);
};
}
@@ -3,27 +3,26 @@
// 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 { drr } 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 (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)),
switchMap((accounts): Observable<DerivedBalances[]> =>
api.derive.balances.votingBalances(accounts)
),
drr()
);
};
}
+4 -4
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 { drr } from '../util';
/**
* @name bestNumber
@@ -24,8 +24,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()),
api.derive.chain.subscribeNewHeads().pipe(
map((header: Header): BlockNumber => header.number.unwrap()),
drr()
);
}
@@ -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 { drr } from '../util';
/**
* @name bestNumberFinalized
@@ -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 { drr } from '../util';
/**
* @name bestNumberLag
@@ -29,8 +27,8 @@ import { bestNumberFinalized } from './bestNumberFinalized';
export function bestNumberLag (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): 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))
+10 -7
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 { drr } from '../util';
/**
* @name bestNumberFinalized
@@ -26,12 +29,12 @@ import { HeaderAndValidators } from './subscribeNewHeads';
*/
export function getHeader (api: ApiInterfaceRx): (hash: Uint8Array | string) => Observable<HeaderExtended | undefined> {
return (hash: Uint8Array | string): Observable<HeaderExtended | undefined> =>
(combineLatest([
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)
),
@@ -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 { drr } from '../util';
/**
* @name subscribeNewHeads
@@ -28,19 +25,11 @@ 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 =>
combineLatest([
api.rpc.chain.subscribeNewHeads(),
api.derive.staking.validators()
]).pipe(
map(([header, { validators }]): HeaderExtended =>
new HeaderExtended(header, validators)
),
drr()
+1 -1
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 { drr } from '../util';
type ResultV2 = [BN, BN, BN, BN, BN, BN, BN, BN, BN, BN];
@@ -12,7 +12,7 @@ import { Option } from '@polkadot/types';
import { isNull } from '@polkadot/util';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util/drr';
import { drr } from '../util';
export function constructInfo (index: BN | number, optionInfo?: Option<ReferendumInfo>): Option<ReferendumInfoExtended> {
const info = optionInfo
@@ -28,13 +28,11 @@ export function constructInfo (index: BN | number, optionInfo?: Option<Referendu
}
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 (index: BN | number): Observable<Option<ReferendumInfoExtended>> =>
api.query.democracy.referendumInfoOf<Option<ReferendumInfo>>(index).pipe(
map((optionInfo): Option<ReferendumInfoExtended> =>
constructInfo(index, optionInfo)
),
drr()
);
}
@@ -11,12 +11,12 @@ import { ApiInterfaceRx } from '@polkadot/api/types';
import { Option, Vec } from '@polkadot/types';
import { ReferendumInfoExtended } from '../type';
import { drr } from '../util/drr';
import { drr } 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 (ids: (BN | number)[] = []): Observable<Option<ReferendumInfoExtended>[]> =>
(
!ids || !ids.length
? of([] as Option<ReferendumInfo>[])
: api.query.democracy.referendumInfoOf.multi(ids) as Observable<Vec<Option<ReferendumInfo>>>
@@ -28,5 +28,4 @@ export function referendumInfos (api: ApiInterfaceRx): (ids?: (BN | number)[]) =
),
drr()
);
};
}
@@ -11,18 +11,16 @@ 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 { drr } 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(
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[] =>
@@ -11,18 +11,17 @@ 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 { drr } from '../util';
export function referendums (api: ApiInterfaceRx): () => Observable<Option<ReferendumInfoExtended>[]> {
return (): Observable<Option<ReferendumInfoExtended>[]> =>
(api.queryMulti([
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)
)
+6 -8
View File
@@ -7,20 +7,18 @@ 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 { drr } from '../util';
export function votes (api: ApiInterfaceRx): (referendumId: BN, accountIds?: AccountId[]) => Observable<Vote[]> {
return (referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> => {
return ((
return (referendumId: BN, accountIds: AccountId[] = []): Observable<Vote[]> =>
(
!accountIds || !accountIds.length
? of([])
: api.query.democracy.voteOf.multi(
? of([] as Vote[])
: api.query.democracy.voteOf.multi<Vote>(
accountIds.map((accountId): [BN, AccountId] =>
[referendumId, accountId]
)
)
) as Observable<Vec<Vote>>).pipe(drr());
};
).pipe(drr());
}
@@ -9,7 +9,7 @@ import { Observable } from 'rxjs';
import { Vec } from '@polkadot/types';
import { switchMap, map } from 'rxjs/operators';
import { approvalFlagsToBools } from '../util/approvalFlagsToBools';
import { drr } from '../util/drr';
import { drr } from '../util';
/**
* @name approvalsOf
@@ -24,21 +24,20 @@ import { drr } from '../util/drr';
* ```
*/
export function approvalsOf (api: ApiInterfaceRx): (who: AccountId) => Observable<boolean[][]> {
return (who: AccountId): 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)
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]
)
),
drr()
);
) as any as Observable<Vec<ApprovalFlag>[]>
),
map((votes: Vec<ApprovalFlag>[]): boolean[][] =>
votes.map((flags: Vec<ApprovalFlag>): boolean[] =>
approvalFlagsToBools(flags)
)
),
drr()
);
}
@@ -4,12 +4,14 @@
import { AccountId, ApprovalFlag, SetIndex } from '@polkadot/types/interfaces';
import { ApiInterfaceRx } from '@polkadot/api/types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { Vec } from '@polkadot/types';
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 { drr } from '../util';
/**
* @name approvalsOfAt
@@ -24,10 +26,9 @@ import { drr } from '../util/drr';
* ```
*/
export function approvalsOfAt (api: ApiInterfaceRx): (who: AccountId, at: SetIndex) => Observable<boolean[]> {
return (who: AccountId, at: SetIndex): Observable<boolean[]> =>
(api.query.elections.approvalsOf<Vec<ApprovalFlag>>([who.toString(), at]))
.pipe(
map((flags: Vec<ApprovalFlag>): boolean[] => approvalFlagsToBools(flags)),
drr()
);
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()
);
}
+76 -37
View File
@@ -2,27 +2,81 @@
// 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 { AccountId, Balance, BlockNumber, SetIndex, VoteIndex } from '@polkadot/types/interfaces';
import { Codec } from '@polkadot/types/types';
import BN from 'bn.js';
import { Observable } from 'rxjs';
import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiInterfaceRx } from '@polkadot/api/types';
import { createType, Vec, u32 } from '@polkadot/types';
import { DerivedElectionsInfo } from '../types';
import { drr } from '../util/drr';
import { drr } from '../util';
function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], AccountId[], BN, BN, SetIndex, BlockNumber, VoteIndex, SetIndex]> {
return api.queryMulti([
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
]) as any;
type ResultElectionsInner = [u32, u32, Vec<[AccountId, BlockNumber] & Codec>, SetIndex, BlockNumber, VoteIndex, SetIndex];
type ResultElections = [Vec<AccountId>, ResultElectionsInner];
function deriveElections ([candidates, [candidateCount, desiredSeats, members, nextVoterSet, termDuration, voteCount, voterCount]]: ResultElections): DerivedElectionsInfo {
return {
candidates,
candidateCount,
desiredSeats,
nextVoterSet,
members: members.map(([accountId]): [AccountId, Balance] => [accountId, createType('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(deriveElections));
}
function derivePhragmen (candidates: AccountId[], members: [AccountId, Balance][], runnersUp: [AccountId, Balance][], candidacyBond: Balance, desiredSeats: u32, termDuration: BlockNumber, votingBond: Balance): DerivedElectionsInfo {
return {
candidates,
candidateCount: createType('u32', candidates.length),
candidacyBond,
desiredSeats,
members,
runnersUp,
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<[AccountId, Balance] & Codec>>(),
api.query.electionsPhragmen.runnersUp<Vec<[AccountId, Balance] & Codec>>()
]).pipe(
map(([candidates, members, runnersUp]): DerivedElectionsInfo => derivePhragmen(
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
))
);
}
/**
@@ -33,31 +87,16 @@ function query (api: ApiInterfaceRx): Observable<[[AccountId, BlockNumber][], Ac
* <BR>
*
* ```javascript
* api.derive.elections.info(([members, candidates]) => {
* api.derive.elections.info(({ members, candidates }) => {
* console.log(`There are currently ${members.length} council members and ${candidates.length} prospective council candidates.`);
* });
* ```
*/
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
} as unknown as DerivedElectionsInfo)),
drr()
);
};
const query = api.query.electionsPhragmen
? queryPhragmen
: queryElections;
return (): Observable<DerivedElectionsInfo> =>
query(api).pipe(drr());
}
@@ -10,7 +10,8 @@ import { DerivedVoterPositions } from '../types';
import BN from 'bn.js';
import { of, combineLatest, Observable } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { drr } from '../util/drr';
import { drr } from '../util';
/**
* @name voterPositions
@@ -34,6 +35,7 @@ export function voterPositions (api: ApiInterfaceRx): () => Observable<DerivedVo
)),
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
+9 -11
View File
@@ -10,8 +10,7 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { createType, Vec } from '@polkadot/types';
import { drr } from '../util/drr';
import { voterPositions } from './voterPositions';
import { drr } from '../util';
/**
* @name voters
@@ -27,15 +26,14 @@ 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))
)
api.derive.elections.voterPositions().pipe(
map((voterPositions: DerivedVoterPositions): Vec<AccountId> =>
createType(
'Vec<AccountId>',
Object.entries(voterPositions)
.sort((a, b): number => a[1].globalIndex.cmp(b[1].globalIndex))
.map(([accountId]): AccountId => createType('AccountId', accountId))
)
),
drr()
);
@@ -3,35 +3,40 @@
// 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 } from '@polkadot/types';
import { Bytes, Option, u32 } from '@polkadot/types';
import { drr } from '../util/drr';
import { drr } 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.query.session
.currentIndex<SessionIndex>()
.pipe(
switchMap((currentIndex): Observable<Bytes[]> =>
api.query.imOnline.receivedHeartbeats.multi(
addresses.map((address): [SessionIndex, AccountId | string] =>
[currentIndex, address]
)
)
),
map((heartbeats): boolean[] =>
heartbeats.map((heartbeat): boolean => !heartbeat.isEmpty)
),
drr()
)
: of([...new Array(addresses.length).keys()].map((): boolean => false));
};
export function receivedHeartbeats (api: ApiInterfaceRx): () => Observable<DerivedHeartbeats> {
return (): 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(([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)
}
}), {})
),
drr()
)
: of({});
}
+2 -2
View File
@@ -6,11 +6,11 @@ import { Observable, from } from 'rxjs';
import ApiRx from '@polkadot/api/rx/Api';
import MockProvider from '@polkadot/rpc-provider/mock';
import { Derive } from '.';
import { ExactDerive } from '.';
const testFunction = (api: ApiRx): any => {
return <
Section extends keyof Derive,
Section extends keyof ExactDerive,
Method extends keyof (typeof api.derive[Section])
>(section: Section, method: Method, inputs: any[]): void => {
describe(`derive.${section}.${method}`, (): void => {
+12 -13
View File
@@ -19,14 +19,13 @@ import * as staking from './staking';
export * from './type';
export type ReturnTypes<Section> = {
type DeriveSection<Section> = {
[Method in keyof Section]: Section[Method] extends AnyFunction
? ReturnType<Section[Method]> // ReturnType<Section[Method]> will be the inner function, i.e. without (api) argument
: never;
};
export type DeriveSections<AllSections> = {
[Section in keyof AllSections]: ReturnTypes<AllSections[Section]>
type DeriveAllSections<AllSections> = {
[Section in keyof AllSections]: DeriveSection<AllSections[Section]>
};
export type DeriveCustom = Record<string, Record<string, (api: ApiInterfaceRx) => (...args: any[]) => Observable<any>>>;
@@ -35,15 +34,15 @@ export type DeriveCustom = Record<string, Record<string, (api: ApiInterfaceRx) =
* Returns an object that will inject `api` into all the functions inside
* `allSections`, and keep the object architecture of `allSections`.
*/
function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSections): DeriveSections<AllSections> {
function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSections): DeriveAllSections<AllSections> {
return Object
.keys(allSections)
.reduce((deriveAcc, sectionName): DeriveSections<AllSections> => {
.reduce((deriveAcc, sectionName): DeriveAllSections<AllSections> => {
const section = allSections[sectionName as keyof AllSections];
deriveAcc[sectionName as keyof AllSections] = Object
.keys(section)
.reduce((sectionAcc, _methodName): ReturnTypes<typeof section> => {
.reduce((sectionAcc, _methodName): DeriveSection<typeof section> => {
const methodName = _methodName as keyof typeof section;
// Not sure what to do here, casting as any. Though the final types are good
const method = (section[methodName] as any)(api);
@@ -51,18 +50,18 @@ function injectFunctions<AllSections> (api: ApiInterfaceRx, allSections: AllSect
(sectionAcc as any)[methodName] = method;
return sectionAcc;
}, {} as unknown as ReturnTypes<typeof section>);
}, {} as DeriveSection<typeof section>);
return deriveAcc;
}, {} as unknown as DeriveSections<AllSections>);
}, {} as DeriveAllSections<AllSections>);
}
export const derive = { accounts, balances, chain, contracts, democracy, elections, imOnline, session, staking };
export type Derive = typeof derive;
export type ExactDerive = DeriveAllSections<typeof derive>;
// FIXME I have no idea how to get this done
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default function decorateDerive (api: ApiInterfaceRx, custom: DeriveCustom = {}) {
// FIXME The return type of this function should be {...ExactDerive, ...DeriveCustom}
// For now we just drop the custom derive typings
export default function decorateDerive (api: ApiInterfaceRx, custom: DeriveCustom = {}): ExactDerive {
return {
...injectFunctions(api, derive),
...injectFunctions(api, custom)
+8 -7
View File
@@ -2,18 +2,19 @@
// 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 { drr } from '../util';
export function eraLength (api: ApiInterfaceRx): () => Observable<BN> {
return (): Observable<BN> =>
info(api)().pipe(
map(({ eraLength }): BN => eraLength),
export function eraLength (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
api.derive.session.info().pipe(
map(({ eraLength }: DerivedSessionInfo): BlockNumber => eraLength),
drr()
);
}
@@ -2,18 +2,19 @@
// 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 { drr } from '../util';
export function eraProgress (api: ApiInterfaceRx): () => Observable<BN> {
return (): Observable<BN> =>
info(api)().pipe(
map(({ eraProgress }): BN => eraProgress),
export function eraProgress (api: ApiInterfaceRx): () => Observable<BlockNumber> {
return (): Observable<BlockNumber> =>
api.derive.session.info().pipe(
map(({ eraProgress }: DerivedSessionInfo): BlockNumber => eraProgress),
drr()
);
}
+1
View File
@@ -4,5 +4,6 @@
export * from './eraLength';
export * from './eraProgress';
export * from './indexes';
export * from './info';
export * from './sessionProgress';

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