From 8f1ed2578d4f67d59d3c1b2f8e837b4e26b830d4 Mon Sep 17 00:00:00 2001 From: Harry Solovay Date: Fri, 21 Oct 2022 15:08:08 -0400 Subject: [PATCH] feat: zones refactor (#280) --- _tasks/dnt.ts | 4 + deps/zones.ts | 1 + effect/BlockRead.ts | 34 +++++ effect/BlockWatch.ts | 39 +++++ effect/EntryRead.ts | 40 ++++++ effect/EntryWatch.ts | 69 +++++++++ effect/ExtrinsicSentWatch.ts | 134 ++++++++++++++++++ effect/KeyPageRead.ts | 62 ++++++++ effect/Metadata.ts | 33 +++++ effect/RpcCall.ts | 47 ++++++ effect/RpcSubscription.ts | 63 ++++++++ effect/atoms/$StorageKey.ts | 17 --- effect/atoms/Decoded.ts | 24 ---- effect/atoms/DeriveCodec.ts | 6 - effect/atoms/Metadata.ts | 48 ------- effect/atoms/RpcCall.ts | 39 ----- effect/atoms/RpcClient.ts | 11 -- effect/atoms/RpcSubscription.ts | 55 ------- effect/atoms/Select.ts | 14 -- effect/atoms/StorageKey.ts | 10 -- effect/atoms/Wrap.ts | 7 - effect/atoms/mod.ts | 13 -- effect/{atoms => }/common.ts | 7 +- .../$Extrinsic.ts => core/$extrinsic.ts} | 6 +- effect/{atoms/$Key.ts => core/$key.ts} | 4 +- effect/core/$storageKey.ts | 14 ++ effect/{atoms/Codec.ts => core/codec.ts} | 4 +- effect/core/decoded.ts | 20 +++ effect/core/deriveCodec.ts | 6 + effect/core/hex.ts | 5 + effect/core/rpcClient.ts | 9 ++ effect/core/storageKey.ts | 10 ++ effect/extrinsic.test.ts | 28 ++-- effect/mod.ts | 13 +- effect/run.ts | 3 + effect/std/common.ts | 0 effect/std/mod.ts | 6 - effect/std/readBlock.ts | 28 ---- effect/std/readEntry.ts | 31 ---- effect/std/readKeyPage.ts | 43 ------ effect/std/submitAndWatchExtrinsic.ts | 124 ---------------- effect/std/watchBlocks.ts | 33 ----- effect/std/watchEntry.ts | 49 ------- effect/sys/Atom.ts | 81 ----------- effect/sys/Atom.type-test.ts | 131 ----------------- effect/sys/Effect.ts | 20 --- effect/sys/key.ts | 18 --- effect/sys/mod.ts | 3 - effect/sys/run.ts | 89 ------------ examples/balance.ts | 4 +- examples/derived.ts | 14 +- examples/first_ten_keys.ts | 4 +- examples/metadata.ts | 4 +- examples/polkadot_js_signer.ts | 5 +- examples/read_block.ts | 4 +- examples/read_events.ts | 4 +- examples/rpc_call.ts | 4 +- examples/rpc_subscription.ts | 4 +- examples/those_of_subxt/read_bonded.ts | 4 +- examples/those_of_subxt/read_era_rewards.ts | 10 +- examples/ticker.ts | 4 +- examples/transfer.ts | 5 +- examples/watch_blocks.ts | 4 +- examples/watch_blocks_iter.ts | 2 +- examples/watch_events.ts | 4 +- mod.ts | 1 + 66 files changed, 664 insertions(+), 972 deletions(-) create mode 100644 deps/zones.ts create mode 100644 effect/BlockRead.ts create mode 100644 effect/BlockWatch.ts create mode 100644 effect/EntryRead.ts create mode 100644 effect/EntryWatch.ts create mode 100644 effect/ExtrinsicSentWatch.ts create mode 100644 effect/KeyPageRead.ts create mode 100644 effect/Metadata.ts create mode 100644 effect/RpcCall.ts create mode 100644 effect/RpcSubscription.ts delete mode 100644 effect/atoms/$StorageKey.ts delete mode 100644 effect/atoms/Decoded.ts delete mode 100644 effect/atoms/DeriveCodec.ts delete mode 100644 effect/atoms/Metadata.ts delete mode 100644 effect/atoms/RpcCall.ts delete mode 100644 effect/atoms/RpcClient.ts delete mode 100644 effect/atoms/RpcSubscription.ts delete mode 100644 effect/atoms/Select.ts delete mode 100644 effect/atoms/StorageKey.ts delete mode 100644 effect/atoms/Wrap.ts delete mode 100644 effect/atoms/mod.ts rename effect/{atoms => }/common.ts (76%) rename effect/{atoms/$Extrinsic.ts => core/$extrinsic.ts} (64%) rename effect/{atoms/$Key.ts => core/$key.ts} (70%) create mode 100644 effect/core/$storageKey.ts rename effect/{atoms/Codec.ts => core/codec.ts} (60%) create mode 100644 effect/core/decoded.ts create mode 100644 effect/core/deriveCodec.ts create mode 100644 effect/core/hex.ts create mode 100644 effect/core/rpcClient.ts create mode 100644 effect/core/storageKey.ts create mode 100644 effect/run.ts delete mode 100644 effect/std/common.ts delete mode 100644 effect/std/mod.ts delete mode 100644 effect/std/readBlock.ts delete mode 100644 effect/std/readEntry.ts delete mode 100644 effect/std/readKeyPage.ts delete mode 100644 effect/std/submitAndWatchExtrinsic.ts delete mode 100644 effect/std/watchBlocks.ts delete mode 100644 effect/std/watchEntry.ts delete mode 100644 effect/sys/Atom.ts delete mode 100644 effect/sys/Atom.type-test.ts delete mode 100644 effect/sys/Effect.ts delete mode 100644 effect/sys/key.ts delete mode 100644 effect/sys/mod.ts delete mode 100644 effect/sys/run.ts diff --git a/_tasks/dnt.ts b/_tasks/dnt.ts index c9ac1f7f5..8637c8e17 100755 --- a/_tasks/dnt.ts +++ b/_tasks/dnt.ts @@ -27,6 +27,10 @@ await Promise.all([ name: "parity-scale-codec", version: "^0.6.1", }, + "https://deno.land/x/zones@v0.1.0-beta.6/mod.ts": { + name: "zones", + version: "0.1.0-beta.6", + }, "deps/smoldot_phantom.ts": { name: "@substrate/smoldot-light", version: "0.6.20", diff --git a/deps/zones.ts b/deps/zones.ts new file mode 100644 index 000000000..3f62bc925 --- /dev/null +++ b/deps/zones.ts @@ -0,0 +1 @@ +export * from "https://deno.land/x/zones@v0.1.0-beta.6/mod.ts"; diff --git a/effect/BlockRead.ts b/effect/BlockRead.ts new file mode 100644 index 000000000..cf86eada3 --- /dev/null +++ b/effect/BlockRead.ts @@ -0,0 +1,34 @@ +import * as Z from "../deps/zones.ts"; +import * as known from "../known/mod.ts"; +import * as U from "../util/mod.ts"; +import { $extrinsic } from "./core/$extrinsic.ts"; +import { deriveCodec } from "./core/deriveCodec.ts"; +import { Metadata } from "./Metadata.ts"; +import { RpcCall } from "./RpcCall.ts"; + +export class BlockRead]> extends Z.Name { + root; + + constructor( + config: known.rpc.Config, + ...[blockHash]: [...Rest] + ) { + super(); + const metadata_ = new Metadata(config, blockHash); + const $extrinsic_ = $extrinsic(deriveCodec(metadata_), metadata_, undefined!); + const call = new RpcCall(config, "chain_getBlock", [blockHash]); + const decoded = Z.call(Z.ls($extrinsic_, call), function mapExtrinsicCall([$extrinsic_, call]) { + const { block: { extrinsics, header }, justifications } = call.result; + return { + justifications, + block: { + header, + extrinsics: extrinsics.map((extrinsic) => { + return $extrinsic_.decode(U.hex.decode(extrinsic)); + }), + }, + }; + }); + this.root = Z.wrap(decoded, "block"); + } +} diff --git a/effect/BlockWatch.ts b/effect/BlockWatch.ts new file mode 100644 index 000000000..a3b6eb94d --- /dev/null +++ b/effect/BlockWatch.ts @@ -0,0 +1,39 @@ +import * as Z from "../deps/zones.ts"; +import { Extrinsic } from "../frame_metadata/mod.ts"; +import * as known from "../known/mod.ts"; +import * as U from "../util/mod.ts"; +import { BlockRead } from "./BlockRead.ts"; +import { RpcCall } from "./RpcCall.ts"; +import { RpcSubscription } from "./RpcSubscription.ts"; +import { run } from "./run.ts"; + +export class BlockWatch extends Z.Name { + root; + + constructor( + config: known.rpc.Config< + string, + "state_getMetadata" | "chain_getBlockHash" | "chain_getBlock" | "chain_unsubscribeNewHead", + "chain_subscribeNewHeads" + >, + createWatchHandler: U.CreateWatchHandler>, + ) { + super(); + this.root = new RpcSubscription( + config, + "chain_subscribeNewHeads", + [], + function subscribeNewHeadsHandler(stop) { + const watchHandler = createWatchHandler(stop); + return async (result) => { + const blockNum = result.params.result.number; + const blockHash = Z.sel(new RpcCall(config, "chain_getBlockHash", [blockNum]), "result"); + // TODO: use derived util from Zones + const block = U.throwIfError(await run(new BlockRead(config, blockHash))); + watchHandler(block.block); + }; + }, + (ok) => new RpcCall(config, "chain_unsubscribeNewHead", [ok.result]), + ); + } +} diff --git a/effect/EntryRead.ts b/effect/EntryRead.ts new file mode 100644 index 000000000..8ba0fa714 --- /dev/null +++ b/effect/EntryRead.ts @@ -0,0 +1,40 @@ +import * as Z from "../deps/zones.ts"; +import * as known from "../known/mod.ts"; +import * as U from "../util/mod.ts"; +import { $storageKey } from "./core/$storageKey.ts"; +import { codec } from "./core/codec.ts"; +import { decoded } from "./core/decoded.ts"; +import { deriveCodec } from "./core/deriveCodec.ts"; +import { storageKey } from "./core/storageKey.ts"; +import { entryMetadata, Metadata, palletMetadata } from "./Metadata.ts"; +import { RpcCall } from "./RpcCall.ts"; + +export class EntryRead< + PalletName extends Z.$, + EntryName extends Z.$, + Keys extends unknown[], + Rest extends [blockHash?: Z.$], +> extends Z.Name { + root; + + constructor( + config: known.rpc.Config, + palletName: PalletName, + entryName: EntryName, + keys: [...Keys], + ...[blockHash]: [...Rest] + ) { + super(); + const metadata_ = new Metadata(config, blockHash); + const deriveCodec_ = deriveCodec(metadata_); + const palletMetadata_ = palletMetadata(metadata_, palletName); + const entryMetadata_ = entryMetadata(palletMetadata_, entryName); + const $storageKey_ = $storageKey(deriveCodec_, palletMetadata_, entryMetadata_); + const storageKey_ = storageKey($storageKey_, ...keys); + const storageCall = new RpcCall(config, "state_getStorage", [storageKey_, blockHash]); + const entryValueTypeI = Z.sel(entryMetadata_, "value"); + const $entry = codec(deriveCodec_, entryValueTypeI); + const resultHex = Z.sel(storageCall, "result"); + this.root = decoded($entry, resultHex, "value"); + } +} diff --git a/effect/EntryWatch.ts b/effect/EntryWatch.ts new file mode 100644 index 000000000..3585890d9 --- /dev/null +++ b/effect/EntryWatch.ts @@ -0,0 +1,69 @@ +import * as Z from "../deps/zones.ts"; +import * as known from "../known/mod.ts"; +import * as rpc from "../rpc/mod.ts"; +import * as U from "../util/mod.ts"; +import { $storageKey } from "./core/$storageKey.ts"; +import { codec } from "./core/codec.ts"; +import { deriveCodec } from "./core/deriveCodec.ts"; +import { storageKey } from "./core/storageKey.ts"; +import { entryMetadata, Metadata, palletMetadata } from "./Metadata.ts"; +import { RpcCall } from "./RpcCall.ts"; +import { RpcSubscription } from "./RpcSubscription.ts"; + +export type WatchEntryEvent = [key?: U.HexString, value?: unknown]; + +type Config = known.rpc.Config< + string, + "state_getMetadata" | "state_unsubscribeStorage", + "state_subscribeStorage" +>; + +export class EntryWatch< + PalletName extends Z.$, + EntryName extends Z.$, + Keys extends unknown[], +> extends Z.Name { + root; + + constructor( + readonly config: Config, + readonly palletName: PalletName, + readonly entryName: EntryName, + readonly keys: Keys, + readonly createWatchHandler: U.CreateWatchHandler, + ) { + super(); + const metadata_ = new Metadata(config); + const deriveCodec_ = deriveCodec(metadata_); + const palletMetadata_ = palletMetadata(metadata_, palletName); + const entryMetadata_ = entryMetadata(palletMetadata_, entryName); + const $storageKey_ = $storageKey(deriveCodec_, palletMetadata_, entryMetadata_); + const entryValueTypeI = Z.sel(entryMetadata_, "value"); + const $entry = codec(deriveCodec_, entryValueTypeI); + const storageKeys = Z.call( + storageKey($storageKey_, ...keys.length ? [keys] : []), + function wrapWithList(v) { + return [v]; + }, + ); + const watchInit = Z.call($entry, function entryWatchInit($entry) { + return U.mapCreateWatchHandler( + createWatchHandler, + (message: rpc.NotifMessage) => { + return message.params.result.changes.map(([key, val]) => { + return [key, val ? $entry.decode(U.hex.decode(val)) : undefined]; + }); + }, + ); + }); + this.root = new RpcSubscription( + config, + "state_subscribeStorage", + [storageKeys], + watchInit, + (ok) => { + return new RpcCall(config, "state_unsubscribeStorage", [ok.result]); + }, + ); + } +} diff --git a/effect/ExtrinsicSentWatch.ts b/effect/ExtrinsicSentWatch.ts new file mode 100644 index 000000000..f1d95d02d --- /dev/null +++ b/effect/ExtrinsicSentWatch.ts @@ -0,0 +1,134 @@ +import { unimplemented } from "../deps/std/testing/asserts.ts"; +import * as Z from "../deps/zones.ts"; +import * as M from "../frame_metadata/mod.ts"; +import * as known from "../known/mod.ts"; +import * as rpc from "../rpc/mod.ts"; +import * as ss58 from "../ss58/mod.ts"; +import * as U from "../util/mod.ts"; +import { $extrinsic } from "./core/$extrinsic.ts"; +import { deriveCodec } from "./core/deriveCodec.ts"; +import { hexDecode } from "./core/hex.ts"; +import { Metadata } from "./Metadata.ts"; +import { RpcCall } from "./RpcCall.ts"; +import { RpcSubscription } from "./RpcSubscription.ts"; + +export { type Config as SendAndWatchExtrinsicConfig }; +type Config = known.rpc.Config< + string, + | "state_getMetadata" + | "state_getRuntimeVersion" + | "chain_getBlockHash" + | "system_accountNextIndex" + | "system_chain" + | "author_unwatchExtrinsic", + "author_submitAndWatchExtrinsic" +>; + +export interface SendAndWatchExtrinsicProps { + sender: M.MultiAddress; + palletName: string; + methodName: string; + args: Record; + checkpoint?: U.HashHexString; + mortality?: [period: bigint, phase: bigint]; + nonce?: string; + tip?: bigint; + sign: M.SignExtrinsic; + createWatchHandler: U.CreateWatchHandler< + rpc.NotifMessage + >; +} + +export class ExtrinsicSentWatch> extends Z.Name { + root; + + constructor( + readonly config: Config, + readonly props_: Props, + ) { + super(); + const props = props_ as Z.Rec$Access; + const metadata_ = new Metadata(config); + const deriveCodec_ = deriveCodec(metadata_); + const $extrinsic_ = $extrinsic(deriveCodec_, metadata_, props.sign, config.addressPrefix); + const runtimeVersion = new RpcCall(config, "state_getRuntimeVersion", []); + const senderSs58 = Z.call(props.sender, function senderSs58(sender) { + return ((): string => { + switch (sender.type) { + case "Id": { + return ss58.encode(config.addressPrefix, sender.value); + } + // TODO: other types + default: { + unimplemented(); + } + } + })() as U.AccountIdString; + }); + const accountNextIndex = new RpcCall(config, "system_accountNextIndex", [senderSs58]); + const genesisHash = hexDecode(Z.sel(new RpcCall(config, "chain_getBlockHash", [0]), "result")); + const checkpointHash = props.checkpoint + ? Z.call(props.checkpoint, function checkpointOrUndef(v) { + return v ? U.hex.decode(v) : v; + }) + : genesisHash; + const extrinsicHex = Z.call( + Z.ls( + $extrinsic_, + props.sender, + props.methodName, + props.palletName, + runtimeVersion, + accountNextIndex, + genesisHash, + props.args, + checkpointHash, + props.tip, + props.mortality, + ), + async function formExtrinsicHex([ + $extrinsic, + sender, + methodName, + palletName, + { result: { specVersion, transactionVersion } }, + { result: nonce }, + genesisHash, + args, + checkpoint, + tip, + mortality, + ]) { + const extrinsicBytes = await $extrinsic.encodeAsync({ + protocolVersion: 4, // TODO: grab this from elsewhere + palletName, + methodName, + args, + signature: { + address: sender, + extra: [ + mortality + ? { + type: "Mortal", + value: mortality, + } + : { type: "Immortal" }, + nonce, + tip || 0, + ], + additional: [specVersion, transactionVersion, checkpoint, genesisHash], + }, + }); + return U.hex.encode(extrinsicBytes) as U.HexString; + }, + ); + this.root = new RpcSubscription( + config, + "author_submitAndWatchExtrinsic", + [extrinsicHex], + props.createWatchHandler, + // TODO: use effect system for cbs such as this + (ok) => new RpcCall(config, "author_unwatchExtrinsic", [ok.result]), + ); + } +} diff --git a/effect/KeyPageRead.ts b/effect/KeyPageRead.ts new file mode 100644 index 000000000..7bb18e11f --- /dev/null +++ b/effect/KeyPageRead.ts @@ -0,0 +1,62 @@ +import * as Z from "../deps/zones.ts"; +import * as known from "../known/mod.ts"; +import * as U from "../util/mod.ts"; +import { $key } from "./core/$key.ts"; +import { $storageKey } from "./core/$storageKey.ts"; +import { deriveCodec } from "./core/deriveCodec.ts"; +import { storageKey } from "./core/storageKey.ts"; +import { entryMetadata, Metadata, palletMetadata } from "./Metadata.ts"; +import { RpcCall } from "./RpcCall.ts"; + +export class KeyPageRead< + PalletName extends Z.$, + EntryName extends Z.$, + Count extends Z.$, + Rest extends [start?: unknown[] | undefined, blockHash?: Z.$], +> extends Z.Name { + root; + + constructor( + config: known.rpc.Config, + palletName: PalletName, + entryName: EntryName, + count: Count, + ...[start, blockHash]: [...Rest] + ) { + super(); + const metadata_ = new Metadata(config, blockHash as Rest[1]); + const deriveCodec_ = deriveCodec(metadata_); + const palletMetadata_ = palletMetadata(metadata_, palletName); + const entryMetadata_ = Z.call( + entryMetadata(palletMetadata_, entryName), + function assertIsMap(entryMetadata) { + if (entryMetadata.type !== "Map") { + return new ReadingKeysOfNonMapError(); + } + return entryMetadata; + }, + ); + const $storageKey_ = $storageKey(deriveCodec_, palletMetadata_, entryMetadata_); + const startKey = start ? storageKey($storageKey_, start) : undefined; + const storageKey_ = storageKey($storageKey_); + const call = new RpcCall(config, "state_getKeysPaged", [ + storageKey_, + count, + startKey, + blockHash as Rest[1], + ]); + const $key_ = $key(deriveCodec_, palletMetadata_, entryMetadata_); + const keysEncoded = Z.sel(call, "result"); + const keysDecoded = Z.call( + Z.ls($key_, keysEncoded), + function keysDecodedImpl([$key, keysEncoded]) { + return keysEncoded.map((keyEncoded) => { + return $key.decode(U.hex.decode(keyEncoded)); + }); + }, + ); + this.root = Z.wrap(keysDecoded, "keys"); + } +} + +export class ReadingKeysOfNonMapError extends U.ErrorCtor("ReadingKeysOfNonMap") {} diff --git a/effect/Metadata.ts b/effect/Metadata.ts new file mode 100644 index 000000000..9095ad2ef --- /dev/null +++ b/effect/Metadata.ts @@ -0,0 +1,33 @@ +import * as Z from "../deps/zones.ts"; +import * as M from "../frame_metadata/mod.ts"; +import * as known from "../known/mod.ts"; +import * as U from "../util/mod.ts"; +import { RpcCall } from "./RpcCall.ts"; + +export class Metadata]> extends Z.Name { + root; + + constructor(config: known.rpc.Config, ...[blockHash]: [...Rest]) { + super(); + this.root = Z.call( + new RpcCall(config, "state_getMetadata", [blockHash]), + function metadataImpl(call) { + try { + return M.fromPrefixedHex(call.result); + } catch (e) { + return new MetadataDecodeError(e); + } + }, + ); + } +} + +export const palletMetadata = Z.call.fac(M.getPallet); +export const entryMetadata = Z.call.fac(M.getEntry); + +export class MetadataDecodeError extends U.ErrorCtor("MetadataDecode") { + // TODO: replace with internal scale error & ensure appropriate trace info + constructor(readonly scaleError: unknown) { + super(); + } +} diff --git a/effect/RpcCall.ts b/effect/RpcCall.ts new file mode 100644 index 000000000..f73807673 --- /dev/null +++ b/effect/RpcCall.ts @@ -0,0 +1,47 @@ +import { Config } from "../config/mod.ts"; +import * as Z from "../deps/zones.ts"; +import * as rpc from "../rpc/mod.ts"; +import { RpcError } from "./common.ts"; +import { rpcClient } from "./core/rpcClient.ts"; + +export class RpcCall< + Methods extends rpc.ProviderMethods, + MethodName extends Z.$>, + Params extends Z.Ls$]>>, +> extends Z.Name { + root; + + constructor( + config: Config, + methodName: MethodName, + params: [...Params], + ) { + super(); + const client = rpcClient(config); + const deps = Z.ls(client, methodName, ...params); + this.root = Z.call( + Z.ls(deps, Z.rc(client, deps)), + async function rpcCallImpl([[client, methodName, ...params], rc]) { + const result = await client.call( + methodName, + params as Parameters<(Methods & rpc.ProviderMethods)[Z.T]>, + ); + if (result.error) { + return new RpcError({ + ...result.error, + attempt: { + methodName, + params, + }, + }); + } + if (rc() == 1) { + const close = await client.close(); + if (close instanceof Error) return close; + } + // TODO: should this effect implicitly index into `result`? + return result; + }, + ); + } +} diff --git a/effect/RpcSubscription.ts b/effect/RpcSubscription.ts new file mode 100644 index 000000000..3215e788d --- /dev/null +++ b/effect/RpcSubscription.ts @@ -0,0 +1,63 @@ +import { Config } from "../config/mod.ts"; +import * as Z from "../deps/zones.ts"; +import * as rpc from "../rpc/mod.ts"; +import * as U from "../util/mod.ts"; +import { RpcError } from "./common.ts"; +import { rpcClient } from "./core/rpcClient.ts"; +import { run } from "./run.ts"; + +export class RpcSubscription< + Config_ extends Config, + MethodName extends Extract, + MethodName_ extends Z.$, + Params extends Parameters]>, + Params_ extends Z.Ls$, + CreateListenerCb extends Z.$>>, +> extends Z.Name { + root; + + constructor( + config: Config_, + methodName: MethodName_, + params: [...Params_], + createListenerCb: CreateListenerCb, + cleanup?: (initOk: rpc.OkMessage) => Z.EffectLike, + ) { + super(); + const client = rpcClient(config); + const deps = Z.ls(client, methodName, createListenerCb, ...params); + this.root = Z.call( + Z.ls(deps, Z.rc(client, deps)), + async function rpcSubscriptionImpl([[client, methodName, createListenerCb, ...params], rc]) { + const result = await client.subscribe( + methodName as MethodName, + params as Parameters, + createListenerCb as any, + cleanup ? (x) => run(cleanup(x.result), undefined!) : undefined, + ); + if (result?.error) { + return new RpcError({ + ...result.error, + attempt: { + methodName, + params, + }, + }); + } + if (rc() == 1) { + const close = await client.close(); + if (close instanceof Error) return close; + } + // TODO: clean up typings –– should implicitly narrow to `undefined` + return result as undefined; + }, + ); + } +} + +// TODO: handle elsewhere +export class RpcSubscriptionError extends U.ErrorCtor("RpcSubscription") { + constructor(readonly error: rpc.ErrMessage["error"]) { + super(); + } +} diff --git a/effect/atoms/$StorageKey.ts b/effect/atoms/$StorageKey.ts deleted file mode 100644 index cc2981003..000000000 --- a/effect/atoms/$StorageKey.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as M from "../../frame_metadata/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; - -export const $storageKey = atomFactory( - "$StorageKey", - ( - deriveCodec: M.DeriveCodec, - pallet: M.Pallet, - storageEntry: M.StorageEntry, - ) => { - return M.$storageKey({ - deriveCodec, - pallet, - storageEntry, - }); - }, -); diff --git a/effect/atoms/Decoded.ts b/effect/atoms/Decoded.ts deleted file mode 100644 index 6afda805f..000000000 --- a/effect/atoms/Decoded.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as $ from "../../deps/scale.ts"; -import * as U from "../../util/mod.ts"; -import { atom } from "../sys/Atom.ts"; -import { T_, Val } from "../sys/Effect.ts"; - -export function decoded< - Codec extends Val<$.Codec>, - Encoded extends Val, - Key extends Val, ->( - codec: Codec, - encoded: Encoded, - key: Key, -) { - return atom( - "Decoded", - [codec, encoded, key], - // TODO: create `Wrap` util –– this is currently necessary as the decoded value is `unknown`, - // which––left top-level––unifies with error types. - (codec, encoded, key): Record, any> => { - return { [key]: codec.decode(U.hex.decode(encoded)) } as any; - }, - ); -} diff --git a/effect/atoms/DeriveCodec.ts b/effect/atoms/DeriveCodec.ts deleted file mode 100644 index 8e25956d0..000000000 --- a/effect/atoms/DeriveCodec.ts +++ /dev/null @@ -1,6 +0,0 @@ -import * as M from "../../frame_metadata/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; - -export const deriveCodec = atomFactory("DeriveCodec", (metadata: M.Metadata) => { - return M.DeriveCodec(metadata.tys); -}); diff --git a/effect/atoms/Metadata.ts b/effect/atoms/Metadata.ts deleted file mode 100644 index f16877bc9..000000000 --- a/effect/atoms/Metadata.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as M from "../../frame_metadata/mod.ts"; -import * as known from "../../known/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import * as U from "../../util/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; -import { Val } from "../sys/mod.ts"; -import { rpcCall } from "./RpcCall.ts"; - -type ConfigConstraint = known.rpc.Config; - -export function metadata]>( - config: ConfigConstraint, - ...[blockHash]: Rest -) { - const call = rpcCall(config, "state_getMetadata", [blockHash]); - return parseMetadata(call); -} - -export const parseMetadata = atomFactory("Metadata", ( - call: rpc.OkMessage, -) => { - try { - return M.fromPrefixedHex(call.result); - } catch (e) { - return new MetadataDecodeError(e); - } -}); - -export const palletMetadata = atomFactory("PalletMetadata", ( - metadata: M.Metadata, - palletName: string, -) => { - return M.getPallet(metadata, palletName); -}); - -export const entryMetadata = atomFactory("EntryMetadata", ( - palletMetadata: M.Pallet, - entryName: string, -) => { - return M.getEntry(palletMetadata, entryName); -}); - -export class MetadataDecodeError extends U.ErrorCtor("MetadataDecode") { - // TODO: replace with internal scale error & ensure appropriate trace info - constructor(readonly scaleError: unknown) { - super(); - } -} diff --git a/effect/atoms/RpcCall.ts b/effect/atoms/RpcCall.ts deleted file mode 100644 index fb90ae0f9..000000000 --- a/effect/atoms/RpcCall.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Config } from "../../config/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import { atom } from "../sys/Atom.ts"; -import { T_, Val, ValCollection } from "../sys/Effect.ts"; -import { RpcError } from "./common.ts"; -import { rpcClient } from "./RpcClient.ts"; - -export function rpcCall< - Methods extends rpc.ProviderMethods, - MethodName extends Val>, - Params extends ValCollection]>>, ->( - config: Config, - methodName: MethodName, - params: Params, -) { - return atom( - "RpcCall", - [rpcClient(config), methodName, ...params], - async (client, methodName, ...params) => { - // TODO: clean up typings - const result = await client.call( - methodName, - params as Parameters<(Methods & rpc.ProviderMethods)[T_]>, - ); - if (result.error) { - return new RpcError({ - ...result.error, - attempt: { - methodName, - params, - }, - }); - } - // TODO: should this effect implicitly index into `result`? - return result; - }, - ); -} diff --git a/effect/atoms/RpcClient.ts b/effect/atoms/RpcClient.ts deleted file mode 100644 index 7ed2b95dc..000000000 --- a/effect/atoms/RpcClient.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Config } from "../../config/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import { atom } from "../sys/Atom.ts"; - -export function rpcClient>(config: C) { - return atom("RpcClient", [config], (config) => { - return rpc.stdClient(config); - }, async (client) => { - await client.close(); - }); -} diff --git a/effect/atoms/RpcSubscription.ts b/effect/atoms/RpcSubscription.ts deleted file mode 100644 index a681297b6..000000000 --- a/effect/atoms/RpcSubscription.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Config } from "../../config/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import * as U from "../../util/mod.ts"; -import { AnyAtom, atom } from "../sys/Atom.ts"; -import { T_, Val, ValCollection } from "../sys/Effect.ts"; -import { RpcError } from "./common.ts"; -import { rpcClient } from "./RpcClient.ts"; - -export function rpcSubscription< - Config_ extends Config, - MethodName extends Extract, - MethodName_ extends Val, - Params extends Parameters]>, - Params_ extends ValCollection, ->( - config: Config_, - methodName: MethodName_, - params: Params_, - createListener: U.CreateWatchHandler>, - cleanup?: (initOk: rpc.OkMessage) => AnyAtom, -) { - return atom( - "RpcSubscription", - [rpcClient(config), methodName, ...params], - async function(client, methodName, ...params) { - const result = await client.subscribe( - methodName as MethodName, - params as Parameters["RpcSubscriptionMethods"][MethodName]>, - createListener, - cleanup - ? (x) => { - return this.run(cleanup(x.result)); - } - : undefined, - ); - if (result?.error) { - return new RpcError({ - ...result.error, - attempt: { - methodName, - params, - }, - }); - } - // TODO: clean up typings –– should implicitly narrow to `undefined` - return result as undefined; - }, - ); -} - -export class RpcSubscriptionError extends U.ErrorCtor("RpcSubscription") { - constructor(readonly error: rpc.ErrMessage["error"]) { - super(); - } -} diff --git a/effect/atoms/Select.ts b/effect/atoms/Select.ts deleted file mode 100644 index 6e6b879a7..000000000 --- a/effect/atoms/Select.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as sys from "../sys/mod.ts"; - -export function select< - T, - Field extends sys.Val>, ->(val: T, field: Field) { - return sys.atom( - "Select", - [val, field], - (val, field): sys.T_[Extract, keyof sys.T_>] => { - return (val as any)[field]; - }, - ); -} diff --git a/effect/atoms/StorageKey.ts b/effect/atoms/StorageKey.ts deleted file mode 100644 index 99dc873ae..000000000 --- a/effect/atoms/StorageKey.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as $ from "../../deps/scale.ts"; -import * as U from "../../util/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; - -export const storageKey = atomFactory( - "StorageKey", - ($storageKey: $.Codec, ...keys: unknown[]) => { - return U.hex.encode($storageKey.encode(keys)) as U.HexString; - }, -); diff --git a/effect/atoms/Wrap.ts b/effect/atoms/Wrap.ts deleted file mode 100644 index 5037d916d..000000000 --- a/effect/atoms/Wrap.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { atom, T_, Val } from "../sys/mod.ts"; - -export function wrap>(target: T, key: K) { - return atom("Wrap", [target, key], (target, key): Record, T_> => { - return { [key]: target } as any; - }); -} diff --git a/effect/atoms/mod.ts b/effect/atoms/mod.ts deleted file mode 100644 index 78843a939..000000000 --- a/effect/atoms/mod.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from "./$Extrinsic.ts"; -export * from "./$Key.ts"; -export * from "./$StorageKey.ts"; -export * from "./Codec.ts"; -export * from "./Decoded.ts"; -export * from "./DeriveCodec.ts"; -export * from "./Metadata.ts"; -export * from "./RpcCall.ts"; -export * from "./RpcClient.ts"; -export * from "./RpcSubscription.ts"; -export * from "./Select.ts"; -export * from "./StorageKey.ts"; -export * from "./Wrap.ts"; diff --git a/effect/atoms/common.ts b/effect/common.ts similarity index 76% rename from effect/atoms/common.ts rename to effect/common.ts index 5ac9c9653..01ebb15c9 100644 --- a/effect/atoms/common.ts +++ b/effect/common.ts @@ -1,7 +1,8 @@ -import { Config } from "../../config/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import * as U from "../../util/mod.ts"; +import { Config } from "../config/mod.ts"; +import * as rpc from "../rpc/mod.ts"; +import * as U from "../util/mod.ts"; +// TODO: handle this elsewhere export class RpcError< Config_ extends Config, MethodName extends keyof Config_["RpcMethods"], diff --git a/effect/atoms/$Extrinsic.ts b/effect/core/$extrinsic.ts similarity index 64% rename from effect/atoms/$Extrinsic.ts rename to effect/core/$extrinsic.ts index 8923f6313..a08070103 100644 --- a/effect/atoms/$Extrinsic.ts +++ b/effect/core/$extrinsic.ts @@ -1,10 +1,10 @@ +import * as Z from "../../deps/zones.ts"; import * as M from "../../frame_metadata/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; -export const $extrinsic = atomFactory("ExtrinsicCodec", ( +export const $extrinsic = Z.call.fac(( deriveCodec: M.DeriveCodec, metadata: M.Metadata, - sign?: M.SignExtrinsic, + sign: M.SignExtrinsic, prefix?: number, ) => { return M.$extrinsic({ diff --git a/effect/atoms/$Key.ts b/effect/core/$key.ts similarity index 70% rename from effect/atoms/$Key.ts rename to effect/core/$key.ts index 63c2f0ae1..13ec2412f 100644 --- a/effect/atoms/$Key.ts +++ b/effect/core/$key.ts @@ -1,7 +1,7 @@ +import * as Z from "../../deps/zones.ts"; import * as M from "../../frame_metadata/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; -export const $key = atomFactory("KeyCodec", ( +export const $key = Z.call.fac(( deriveCodec: M.DeriveCodec, pallet: M.Pallet, storageEntry: M.StorageEntry, diff --git a/effect/core/$storageKey.ts b/effect/core/$storageKey.ts new file mode 100644 index 000000000..6398e3b00 --- /dev/null +++ b/effect/core/$storageKey.ts @@ -0,0 +1,14 @@ +import * as Z from "../../deps/zones.ts"; +import * as M from "../../frame_metadata/mod.ts"; + +export const $storageKey = Z.call.fac(( + deriveCodec: M.DeriveCodec, + pallet: M.Pallet, + storageEntry: M.StorageEntry, +) => { + return M.$storageKey({ + deriveCodec, + pallet, + storageEntry, + }); +}); diff --git a/effect/atoms/Codec.ts b/effect/core/codec.ts similarity index 60% rename from effect/atoms/Codec.ts rename to effect/core/codec.ts index e87462073..4df72cfc6 100644 --- a/effect/atoms/Codec.ts +++ b/effect/core/codec.ts @@ -1,7 +1,7 @@ +import * as Z from "../../deps/zones.ts"; import * as M from "../../frame_metadata/mod.ts"; -import { atomFactory } from "../sys/Atom.ts"; -export const codec = atomFactory("Codec", ( +export const codec = Z.call.fac(( deriveCodec: M.DeriveCodec, ty: number | M.Ty, ) => { diff --git a/effect/core/decoded.ts b/effect/core/decoded.ts new file mode 100644 index 000000000..429919e3f --- /dev/null +++ b/effect/core/decoded.ts @@ -0,0 +1,20 @@ +import * as $ from "../../deps/scale.ts"; +import * as Z from "../../deps/zones.ts"; +import * as U from "../../util/mod.ts"; + +export function decoded< + Codec extends Z.$<$.Codec>, + Encoded extends Z.$, + Key extends Z.$, +>( + codec: Codec, + encoded: Encoded, + key: Key, +) { + return Z.call( + Z.ls(codec, encoded, key), + function decodedImpl([codec, encoded, key]): Record, any> { + return { [key]: codec.decode(U.hex.decode(encoded)) } as any; + }, + ); +} diff --git a/effect/core/deriveCodec.ts b/effect/core/deriveCodec.ts new file mode 100644 index 000000000..e6e75c1d3 --- /dev/null +++ b/effect/core/deriveCodec.ts @@ -0,0 +1,6 @@ +import * as Z from "../../deps/zones.ts"; +import * as M from "../../frame_metadata/mod.ts"; + +export const deriveCodec = Z.call.fac((metadata: M.Metadata) => { + return M.DeriveCodec(metadata.tys); +}); diff --git a/effect/core/hex.ts b/effect/core/hex.ts new file mode 100644 index 000000000..bce33905f --- /dev/null +++ b/effect/core/hex.ts @@ -0,0 +1,5 @@ +import * as Z from "../../deps/zones.ts"; +import * as U from "../../util/mod.ts"; + +export const hexEncode = Z.call.fac(U.hex.encode); +export const hexDecode = Z.call.fac(U.hex.decode); diff --git a/effect/core/rpcClient.ts b/effect/core/rpcClient.ts new file mode 100644 index 000000000..01806eb60 --- /dev/null +++ b/effect/core/rpcClient.ts @@ -0,0 +1,9 @@ +import { Config } from "../../config/mod.ts"; +import * as Z from "../../deps/zones.ts"; +import * as rpc from "../../rpc/mod.ts"; + +export function rpcClient(config: C) { + return Z.call(config, function rpcClientImpl() { + return rpc.stdClient(config); + }); +} diff --git a/effect/core/storageKey.ts b/effect/core/storageKey.ts new file mode 100644 index 000000000..23d6f54b2 --- /dev/null +++ b/effect/core/storageKey.ts @@ -0,0 +1,10 @@ +import * as $ from "../../deps/scale.ts"; +import * as Z from "../../deps/zones.ts"; +import * as U from "../../util/mod.ts"; + +export const storageKey = Z.call.fac(( + $storageKey: $.Codec, + ...keys: unknown[] +) => { + return U.hex.encode($storageKey.encode(keys)) as U.HexString; +}); diff --git a/effect/extrinsic.test.ts b/effect/extrinsic.test.ts index ea0b5fb69..f9ca1fcc7 100644 --- a/effect/extrinsic.test.ts +++ b/effect/extrinsic.test.ts @@ -3,14 +3,15 @@ import { assertEquals, assertObjectMatch } from "../deps/std/testing/asserts.ts" import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; +import { run } from "./run.ts"; Deno.test({ name: "Balances.transfer", fn: async (ctx) => { await ctx.step("extrinsic events", async () => { const extrinsicEvents: string[] = await collectExtrinsicEvents( + T.westend, { - config: T.westend, palletName: "Balances", methodName: "transfer", args: { @@ -23,17 +24,13 @@ Deno.test({ }, T.alice, ); - assertEquals(extrinsicEvents, ["ready", "inBlock", "finalized"]); }); await ctx.step({ name: "account balance updated", fn: async () => { - const root = C.readEntry(T.westend, "System", "Account", [T.bob.publicKey]); - - const state = await root.run(); - + const state = await run(new C.EntryRead(T.westend, "System", "Account", [T.bob.publicKey])); assertObjectMatch(state, { value: { data: { free: 10000000000012345n } } }); }, }); @@ -45,8 +42,8 @@ Deno.test({ fn: async (ctx) => { await ctx.step("extrinsic events", async () => { const extrinsicEvents: string[] = await collectExtrinsicEvents( + T.westend, { - config: T.westend, palletName: "Treasury", methodName: "propose_spend", args: { @@ -70,8 +67,8 @@ Deno.test({ fn: async (ctx) => { await ctx.step("extrinsic events", async () => { const extrinsicEvents: string[] = await collectExtrinsicEvents( + T.westend, { - config: T.westend, palletName: "Democracy", methodName: "propose", args: { @@ -83,23 +80,22 @@ Deno.test({ }, T.alice, ); - assertEquals(extrinsicEvents, ["ready", "inBlock", "finalized"]); }); }, }); async function collectExtrinsicEvents( - { config, palletName, methodName, args }: Pick< + config: C.Config, + { palletName, methodName, args }: Pick< C.SendAndWatchExtrinsicProps, - "config" | "palletName" | "methodName" | "args" + "palletName" | "methodName" | "args" >, sender: KeyringPair, ): Promise { const extrinsicEvents: string[] = []; - - const root = C.sendAndWatchExtrinsic({ - config, + // TODO: get rid of this `any` + const root = new C.ExtrinsicSentWatch(config as any, { sender: { type: "Id", value: sender.publicKey, @@ -130,8 +126,6 @@ async function collectExtrinsicEvents( }; }, }); - - await root.run(); - + U.throwIfError(await run(root)); return extrinsicEvents; } diff --git a/effect/mod.ts b/effect/mod.ts index 026124d75..49207de9d 100644 --- a/effect/mod.ts +++ b/effect/mod.ts @@ -1,3 +1,10 @@ -export * from "./atoms/mod.ts"; -export * from "./std/mod.ts"; -export * from "./sys/mod.ts"; +export * from "./BlockRead.ts"; +export * from "./BlockWatch.ts"; +export * from "./EntryRead.ts"; +export * from "./EntryWatch.ts"; +export * from "./ExtrinsicSentWatch.ts"; +export * from "./KeyPageRead.ts"; +export * from "./Metadata.ts"; +export * from "./RpcCall.ts"; +export * from "./RpcSubscription.ts"; +export * from "./run.ts"; diff --git a/effect/run.ts b/effect/run.ts new file mode 100644 index 000000000..d9e7b01a2 --- /dev/null +++ b/effect/run.ts @@ -0,0 +1,3 @@ +import * as Z from "../deps/zones.ts"; + +export const run = Z.runtime(); diff --git a/effect/std/common.ts b/effect/std/common.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/effect/std/mod.ts b/effect/std/mod.ts deleted file mode 100644 index f24813c44..000000000 --- a/effect/std/mod.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from "./readBlock.ts"; -export * from "./readEntry.ts"; -export * from "./readKeyPage.ts"; -export * from "./submitAndWatchExtrinsic.ts"; -export * from "./watchBlocks.ts"; -export * from "./watchEntry.ts"; diff --git a/effect/std/readBlock.ts b/effect/std/readBlock.ts deleted file mode 100644 index ad47b2560..000000000 --- a/effect/std/readBlock.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as known from "../../known/mod.ts"; -import * as U from "../../util/mod.ts"; -import * as a from "../atoms/mod.ts"; -import * as sys from "../sys/mod.ts"; - -type Config = known.rpc.Config; - -export function readBlock]>( - config: Config, - ...[blockHash]: Rest -) { - const metadata_ = a.metadata(config, blockHash); - const $extrinsic = a.$extrinsic(a.deriveCodec(metadata_), metadata_); - const call = a.rpcCall(config, "chain_getBlock", [blockHash]); - const decoded = sys.anon([$extrinsic, call], ($extrinsic, call) => { - const { block: { extrinsics, header }, justifications } = call.result; - return { - justifications, - block: { - header, - extrinsics: extrinsics.map((extrinsic) => { - return $extrinsic.decode(U.hex.decode(extrinsic)); - }), - }, - }; - }); - return a.wrap(decoded, "block"); -} diff --git a/effect/std/readEntry.ts b/effect/std/readEntry.ts deleted file mode 100644 index 673e07809..000000000 --- a/effect/std/readEntry.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as known from "../../known/mod.ts"; -import * as U from "../../util/mod.ts"; -import * as a from "../atoms/mod.ts"; -import * as sys from "../sys/mod.ts"; - -type Config = known.rpc.Config; - -export function readEntry< - PalletName extends sys.Val, - EntryName extends sys.Val, - Keys extends unknown[], - Rest extends [blockHash?: sys.Val], ->( - config: Config, - palletName: PalletName, - entryName: EntryName, - keys: Keys, - ...[blockHash]: Rest -) { - const metadata_ = a.metadata(config, blockHash); - const deriveCodec_ = a.deriveCodec(metadata_); - const palletMetadata_ = a.palletMetadata(metadata_, palletName); - const entryMetadata_ = a.entryMetadata(palletMetadata_, entryName); - const $storageKey = a.$storageKey(deriveCodec_, palletMetadata_, entryMetadata_); - const storageKey = a.storageKey($storageKey, ...keys); - const storageCall = a.rpcCall(config, "state_getStorage", [storageKey, blockHash]); - const entryValueTypeI = a.select(entryMetadata_, "value"); - const $entry = a.codec(deriveCodec_, entryValueTypeI); - const resultHex = a.select(storageCall, "result"); - return a.decoded($entry, resultHex, "value"); -} diff --git a/effect/std/readKeyPage.ts b/effect/std/readKeyPage.ts deleted file mode 100644 index fc77b5357..000000000 --- a/effect/std/readKeyPage.ts +++ /dev/null @@ -1,43 +0,0 @@ -import * as known from "../../known/mod.ts"; -import * as U from "../../util/mod.ts"; -import * as a from "../atoms/mod.ts"; -import * as sys from "../sys/mod.ts"; - -type Config = known.rpc.Config; - -export function readKeyPage< - PalletName extends sys.Val, - EntryName extends sys.Val, - Count extends sys.Val, - Rest extends [start?: unknown[] | undefined, blockHash?: sys.Val], ->( - config: Config, - palletName: PalletName, - entryName: EntryName, - count: Count, - ...[start, blockHash]: Rest -) { - const metadata = a.metadata(config, blockHash); - const deriveCodec = a.deriveCodec(metadata); - const palletMetadata = a.palletMetadata(metadata, palletName); - const entryMetadata = sys.anon([a.entryMetadata(palletMetadata, entryName)], (entryMetadata) => { - if (entryMetadata.type !== "Map") { - return new ReadingKeysOfNonMapError(); - } - return entryMetadata; - }); - const $storageKey = a.$storageKey(deriveCodec, palletMetadata, entryMetadata); - const startKey = start ? a.storageKey($storageKey, start) : undefined; - const storageKey = a.storageKey($storageKey); - const call = a.rpcCall(config, "state_getKeysPaged", [storageKey, count, startKey, blockHash]); - const $key = a.$key(deriveCodec, palletMetadata, entryMetadata); - const keysEncoded = a.select(call, "result"); - const keysDecoded = sys.anon([$key, keysEncoded], ($key, keysEncoded) => { - return keysEncoded.map((keyEncoded) => { - return $key.decode(U.hex.decode(keyEncoded)); - }); - }); - return a.wrap(keysDecoded, "keys"); -} - -export class ReadingKeysOfNonMapError extends U.ErrorCtor("ReadingKeysOfNonMap") {} diff --git a/effect/std/submitAndWatchExtrinsic.ts b/effect/std/submitAndWatchExtrinsic.ts deleted file mode 100644 index 512c56ad0..000000000 --- a/effect/std/submitAndWatchExtrinsic.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { unimplemented } from "../../deps/std/testing/asserts.ts"; -import * as M from "../../frame_metadata/mod.ts"; -import * as known from "../../known/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import * as ss58 from "../../ss58/mod.ts"; -import * as U from "../../util/mod.ts"; -import * as a from "../atoms/mod.ts"; -import * as sys from "../sys/mod.ts"; - -export { type Config as SendAndWatchExtrinsicConfig }; -type Config = known.rpc.Config< - string, - | "state_getMetadata" - | "state_getRuntimeVersion" - | "chain_getBlockHash" - | "system_accountNextIndex" - | "system_chain" - | "author_unwatchExtrinsic", - "author_submitAndWatchExtrinsic" ->; - -export interface SendAndWatchExtrinsicProps { - config: Config; - sender: sys.Val; - palletName: sys.Val; - methodName: sys.Val; - args: sys.Val>; - checkpoint?: sys.Val; - mortality?: sys.Val<[period: bigint, phase: bigint]>; - nonce?: sys.Val; - tip?: sys.Val; - sign: M.SignExtrinsic; - createWatchHandler: U.CreateWatchHandler< - rpc.NotifMessage - >; -} - -export function sendAndWatchExtrinsic(props: Props) { - const metadata = a.metadata(props.config); - const deriveCodec = a.deriveCodec(metadata); - const $extrinsic = a.$extrinsic(deriveCodec, metadata, props.sign, props.config.addressPrefix); - const runtimeVersion = a.rpcCall(props.config, "state_getRuntimeVersion", []); - const senderSs58 = sys.anon([props.sender], (sender) => { - return ((): string => { - switch (sender.type) { - case "Id": { - return ss58.encode(props.config.addressPrefix, sender.value); - } - // TODO: other types - default: { - unimplemented(); - } - } - })() as U.AccountIdString; - }); - const accountNextIndex = a.rpcCall(props.config, "system_accountNextIndex", [senderSs58]); - const genesisHash = sys.anon( - [a.rpcCall(props.config, "chain_getBlockHash", [0])], - ({ result }) => { - return U.hex.decode(result); - }, - ); - const checkpointHash = props.checkpoint - ? sys.anon([props.checkpoint], (v) => { - return U.hex.decode(v); - }) - : genesisHash; - const extrinsicHex = sys.anon([ - $extrinsic, - props.sender, - props.methodName, - props.palletName, - runtimeVersion, - accountNextIndex, - genesisHash, - props.args, - checkpointHash, - props.tip, - props.mortality, - ], async ( - $extrinsic, - sender, - methodName, - palletName, - { result: { specVersion, transactionVersion } }, - { result: nonce }, - genesisHash, - args, - checkpoint, - tip, - mortality, - ) => { - const extrinsicBytes = await $extrinsic.encodeAsync({ - protocolVersion: 4, // TODO: grab this from elsewhere - palletName, - methodName, - args, - signature: { - address: sender, - extra: [ - mortality - ? { - type: "Mortal", - value: mortality, - } - : { type: "Immortal" }, - nonce, - tip || 0, - ], - additional: [specVersion, transactionVersion, checkpoint, genesisHash], - }, - }); - return U.hex.encode(extrinsicBytes) as U.HexString; - }); - return a.rpcSubscription( - props.config, - "author_submitAndWatchExtrinsic", - [extrinsicHex], - props.createWatchHandler, - (ok) => { - return a.rpcCall(props.config, "author_unwatchExtrinsic", [ok.result]); - }, - ); -} diff --git a/effect/std/watchBlocks.ts b/effect/std/watchBlocks.ts deleted file mode 100644 index 2188afd3a..000000000 --- a/effect/std/watchBlocks.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Extrinsic } from "../../frame_metadata/mod.ts"; -import * as known from "../../known/mod.ts"; -import * as U from "../../util/mod.ts"; -import * as a from "../atoms/mod.ts"; -import { readBlock } from "./readBlock.ts"; - -type Config = known.rpc.Config< - string, - "state_getMetadata" | "chain_getBlockHash" | "chain_getBlock" | "chain_unsubscribeNewHead", - "chain_subscribeNewHeads" ->; - -export function watchBlocks( - config: Config, - createWatchHandler: U.CreateWatchHandler>, -) { - return a.rpcSubscription(config, "chain_subscribeNewHeads", [], (stop) => { - const watchHandler = createWatchHandler(stop); - return async (result) => { - const blockNum = result.params.result.number; - const blockHash = a - .rpcCall(config, "chain_getBlockHash", [blockNum]) - .select("result"); - const block = U.throwIfError( - // STOP THIS MADNESS - await readBlock(config, blockHash as unknown as U.HashHexString).run(), - ); - watchHandler(block.block); - }; - }, (ok) => { - return a.rpcCall(config, "chain_unsubscribeNewHead", [ok.result]); - }); -} diff --git a/effect/std/watchEntry.ts b/effect/std/watchEntry.ts deleted file mode 100644 index 8aea9a019..000000000 --- a/effect/std/watchEntry.ts +++ /dev/null @@ -1,49 +0,0 @@ -import * as known from "../../known/mod.ts"; -import * as rpc from "../../rpc/mod.ts"; -import * as U from "../../util/mod.ts"; -import * as a from "../atoms/mod.ts"; -import * as sys from "../sys/mod.ts"; - -export type WatchEntryEvent = [key?: U.HexString, value?: unknown]; - -type Config = known.rpc.Config< - string, - "state_getMetadata" | "state_unsubscribeStorage", - "state_subscribeStorage" ->; - -export function watchEntry< - PalletName extends sys.Val, - EntryName extends sys.Val, - Keys extends unknown[], ->( - config: Config, - palletName: PalletName, - entryName: EntryName, - keys: Keys, - createWatchHandler: U.CreateWatchHandler, -) { - const metadata_ = a.metadata(config); - const deriveCodec_ = a.deriveCodec(metadata_); - const palletMetadata_ = a.palletMetadata(metadata_, palletName); - const entryMetadata_ = a.entryMetadata(palletMetadata_, entryName); - const $storageKey = a.$storageKey(deriveCodec_, palletMetadata_, entryMetadata_); - const entryValueTypeI = a.select(entryMetadata_, "value"); - const $entry = a.codec(deriveCodec_, entryValueTypeI); - const storageKeys = keys.length === 0 - ? sys.anon([a.storageKey($storageKey)], (v) => [v]) - : sys.anon([a.storageKey($storageKey, keys)], (v) => [v]); - return sys.into([$entry], ($entryCodec) => { - const watchInit = U.mapCreateWatchHandler( - createWatchHandler, - (message: rpc.NotifMessage) => { - return message.params.result.changes.map(([key, val]) => { - return [key, val ? $entryCodec.decode(U.hex.decode(val)) : undefined]; - }); - }, - ); - return a.rpcSubscription(config, "state_subscribeStorage", [storageKeys], watchInit, (ok) => { - return a.rpcCall(config, "state_unsubscribeStorage", [ok.result]); - }); - }); -} diff --git a/effect/sys/Atom.ts b/effect/sys/Atom.ts deleted file mode 100644 index 4711727bb..000000000 --- a/effect/sys/Atom.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { select } from "../atoms/Select.ts"; -import { E_, Effect, Resolved, T_, Val, ValCollection } from "./Effect.ts"; -import { key } from "./key.ts"; -import { run, RunContext, RunResult } from "./run.ts"; - -export function atom( - fqn: N, - args: [...A], - impl: Impl, - exit?: Exit, -): Atom { - return new Atom(fqn, args, impl, exit); -} - -export class Atom - extends Effect, Extract | E_> -{ - constructor( - fqn: N, - readonly args: A, - readonly impl: Impl, - readonly exit?: Exit, - ) { - super(fqn); - } - - select(field: Val>) { - return select(this, field); - } - - run(): RunResult { - return run(this); - } -} - -export function atomFactory( - fqn: N, - impl: (...args: AR) => R | Promise, - exit?: Exit, -) { - return >(...args: A): Atom => { - return new Atom(fqn, args, impl as Impl, exit); - }; -} - -export type AnyAtom = Atom; - -export type Impl = ( - this: RunContext, - ...args: Resolved -) => R | Promise; - -// TODO: type the possibility of exit errors -export type Exit = (resolved: Exclude) => void | Promise; - -export function anon( - args: [...A], - impl: Impl, - exit?: Exit, -): Atom { - return new Atom(key(impl), args, impl, exit); -} - -export function into( - args: [...A], - into: Impl, -): Atom | E_> | T_>> { - return new Atom("Map", args, async function(...args) { - const next = await into.bind(this)(...args); - if (next instanceof Error) { - return next; - } - return await this.run(next); - }); -} - -export function all(...effects: A): Atom<"All", A, Resolved> { - return new Atom("All", effects, (...resolved) => { - return resolved; - }); -} diff --git a/effect/sys/Atom.type-test.ts b/effect/sys/Atom.type-test.ts deleted file mode 100644 index 0eb30e9eb..000000000 --- a/effect/sys/Atom.type-test.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { IsExact } from "../../deps/conditional_type_checks.ts"; -import { ErrorCtor } from "../../util/mod.ts"; -import { AnyAtom, atom } from "./Atom.ts"; -import { E_, T_, Val } from "./Effect.ts"; - -declare function assert<_InQuestion extends true>(): void; -type EIs = IsExact, Expectation>; -type TIs = IsExact, Expectation>; - -function asOrErr() { - return (val: T) => { - return val as T | E; - }; -} - -export namespace Math { - class _AddError extends ErrorCtor("Add") {} - class _SubtractError extends ErrorCtor("Subtract") {} - class _MultiplyError extends ErrorCtor("Multiply") {} - class _DivideError extends ErrorCtor("Divide") {} - - function add, B extends Val>(a: A, b: B) { - return atom("add", [a, b], (a, b) => { - return asOrErr<_AddError>()(a + b); - }); - } - - function subtract, B extends Val>(a: A, b: B) { - return atom("subtract", [a, b], (a, b) => { - return asOrErr<_SubtractError>()(a + b); - }); - } - - function multiply, B extends Val>(a: A, b: B) { - return atom("multiply", [a, b], (a, b) => { - return asOrErr<_MultiplyError>()(a + b); - }); - } - - function divide, B extends Val>(a: A, b: B) { - return atom("divide", [a, b], (a, b) => { - return asOrErr<_DivideError>()(a + b); - }); - } - - const t0 = add(1, 2); - assert>(); - // @ts-expect-error: _ - assert>(); - assert>(); - - const t1 = add(t0, 3); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - - const t2 = add(t0, t1); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - - const t3 = subtract(10, t2); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t4 = subtract(t2, t3); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t5 = subtract(100, t4); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t6 = multiply(100, 100); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t7 = multiply(t5, 100); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t8 = multiply(t5, t7); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t9 = divide(t8, 2); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - - const t10 = divide(t8, t9); - assert>(); - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); - // @ts-expect-error: _ - assert>(); -} diff --git a/effect/sys/Effect.ts b/effect/sys/Effect.ts deleted file mode 100644 index f06144ba1..000000000 --- a/effect/sys/Effect.ts +++ /dev/null @@ -1,20 +0,0 @@ -declare const T_: unique symbol; -declare const E_: unique symbol; - -export abstract class Effect { - declare [T_]: T; - declare [E_]: E; - - constructor(readonly fqn: N) {} -} - -export type AnyEffect = Effect; - -export type T_ = U extends AnyEffect ? T : U; -export type E_ = U extends Effect ? E : never; - -export type Val = T | AnyEffect; -export type ValCollection = { - [I in keyof C]: I extends `${number}` ? Val : C[I]; -}; -export type Resolved = { [I in keyof C]: T_ }; diff --git a/effect/sys/key.ts b/effect/sys/key.ts deleted file mode 100644 index 4a1a84977..000000000 --- a/effect/sys/key.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Atom } from "./Atom.ts"; - -let i = 0; // TODO: make fqn optional -const refKeys = new Map(); -export function key(val: unknown): string { - let refKey = refKeys.get(val); - if (refKey) { - return refKey; - } - if (val instanceof Atom) { - refKey = `${val.fqn}(${(val.args as any[]).map(key)})`; - refKeys.set(val, refKey); - return refKey; - } - refKey = `_${i++}`; - refKeys.set(val, refKey); - return refKey; -} diff --git a/effect/sys/mod.ts b/effect/sys/mod.ts deleted file mode 100644 index 5ac6a74f9..000000000 --- a/effect/sys/mod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./Atom.ts"; -export * from "./Effect.ts"; -export * from "./run.ts"; diff --git a/effect/sys/run.ts b/effect/sys/run.ts deleted file mode 100644 index c62e508d6..000000000 --- a/effect/sys/run.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { AnyAtom, Atom } from "./Atom.ts"; -import { E_, T_ } from "./Effect.ts"; -import { key } from "./key.ts"; - -// TODO: eventually refactor this to contain `V` / atom-specific runtime -export interface RunContext { - run: Run; -} -export type RunResult = Promise | E_>; -export type Run = (root: Root) => RunResult; - -export const { run } = (new class Runtime implements RunContext { - #cache = new Map>(); // TODO: set max size / use LRU - - run = async (root: Root) => { - const dependents = new Map[]>(); - const cleanup = new Map void | Promise>(); - const cleanupPending: (void | Promise)[] = []; - try { - const rootResult = await this.visit>(root, dependents, cleanup); - for (const [k, v] of dependents) { - const c = cleanup.get(k); - if (c) { - cleanupPending.push((async () => { - await Promise.all(v); - await c(); - })()); - } - } - await Promise.all(cleanupPending); - return rootResult; - } catch (e) { - return e as E_; - } - }; - - visit = ( - val: unknown, - dependents: Map[]>, - cleanup: Map void | Promise>, - ): T | Promise => { - const k = key(val); - if (this.#cache.has(k)) { - return this.#cache.get(k) as Promise; - } - if (val instanceof Atom) { - return (async () => { - const args: any[] = val.args; - const argsPending = Promise.all((args as any[]).map((arg) => { - return this.visit(arg, dependents, cleanup); - })); - const pending = argsPending.then((argsResolved) => { - return val.impl.bind(this)(...argsResolved); - }); - this.#cache.set(k, pending); - args.forEach((arg) => { - if (arg instanceof Atom) { - this.addDependent(dependents, pending, arg); - } - }); - const resolved = await pending; - if (resolved instanceof Error) { - throw resolved; - } - if (val.exit) { - const applied = () => val.exit!(resolved); - cleanup.set(val, applied); - this.#cache.delete(k); - } - return resolved; - })(); - } - return val as T; - }; - - addDependent = ( - dependents: Map[]>, - dependency: Promise, - dependent: AnyAtom, - ) => { - let e = dependents.get(dependent); - if (e) { - e.push(dependency); - } else { - e = [dependency]; - dependents.set(dependent, e); - } - }; -}()); diff --git a/examples/balance.ts b/examples/balance.ts index 9ad3bbac4..6de6c5545 100644 --- a/examples/balance.ts +++ b/examples/balance.ts @@ -2,6 +2,6 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.readEntry(T.polkadot, "System", "Account", [T.alice.publicKey]); +const root = new C.EntryRead(T.polkadot, "System", "Account", [T.alice.publicKey]); -console.log(U.throwIfError(await root.run())); +console.log(U.throwIfError(await C.run(root))); diff --git a/examples/derived.ts b/examples/derived.ts index c39d9893e..8740484a7 100644 --- a/examples/derived.ts +++ b/examples/derived.ts @@ -1,13 +1,13 @@ import * as C from "../mod.ts"; import * as U from "../util/mod.ts"; -const ids = C.readEntry(C.polkadot, "Paras", "Parachains", []); +const ids = new C.EntryRead(C.polkadot, "Paras", "Parachains", []); -const root = C.into([ids], ({ value }) => { - const heads = value.map((id: number) => { - return C.readEntry(C.polkadot, "Paras", "Heads", [id]); - }); - return C.all(...heads); +// TODO: fix error –– client rc goes down to 1 before new reads initialized +// aka., client disconnects before the following reads are evaluated +const root = C.each(C.sel(ids, "value"), (id) => { + return new C.EntryRead(C.polkadot, "Paras", "Heads", [id]); }); -console.log(U.throwIfError(await root.run())); +// @ts-ignore for now +console.log(U.throwIfError(await C.run(root))); diff --git a/examples/first_ten_keys.ts b/examples/first_ten_keys.ts index 92d46820b..7f45d92d5 100644 --- a/examples/first_ten_keys.ts +++ b/examples/first_ten_keys.ts @@ -2,6 +2,6 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.readKeyPage(T.polkadot, "System", "Account", 10); +const root = new C.KeyPageRead(T.polkadot, "System", "Account", 10); -console.log(U.throwIfError(await root.run()).keys); +console.log(U.throwIfError(await C.run(root)).keys); diff --git a/examples/metadata.ts b/examples/metadata.ts index 1f3100f55..994f09b7a 100644 --- a/examples/metadata.ts +++ b/examples/metadata.ts @@ -2,6 +2,6 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.metadata(T.polkadot); +const root = new C.Metadata(T.polkadot); -console.log(U.throwIfError(await root.run())); +console.log(U.throwIfError(await C.run(root))); diff --git a/examples/polkadot_js_signer.ts b/examples/polkadot_js_signer.ts index 5b69e0ff8..acd5f825e 100644 --- a/examples/polkadot_js_signer.ts +++ b/examples/polkadot_js_signer.ts @@ -3,8 +3,7 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.sendAndWatchExtrinsic({ - config: T.westend, +const root = new C.ExtrinsicSentWatch(T.westend, { sender: { type: "Id", value: T.alice.publicKey, @@ -48,4 +47,4 @@ const root = C.sendAndWatchExtrinsic({ }, }); -U.throwIfError(await root.run()); +U.throwIfError(await C.run(root)); diff --git a/examples/read_block.ts b/examples/read_block.ts index a7ce5b74b..93b827beb 100644 --- a/examples/read_block.ts +++ b/examples/read_block.ts @@ -1,6 +1,6 @@ import * as C from "../mod.ts"; import * as U from "../util/mod.ts"; -const root = C.readBlock(C.polkadot); +const root = new C.BlockRead(C.polkadot); -console.log(U.throwIfError(await root.run())); +console.log(U.throwIfError(await C.run(root))); diff --git a/examples/read_events.ts b/examples/read_events.ts index ff7a52cdd..9a1987e13 100644 --- a/examples/read_events.ts +++ b/examples/read_events.ts @@ -1,6 +1,6 @@ import * as C from "../mod.ts"; import * as U from "../util/mod.ts"; -const root = C.readEntry(C.westend, "System", "Events", []); +const root = new C.EntryRead(C.polkadot, "System", "Events", []); -console.log(U.throwIfError(await root.run())); +console.log(U.throwIfError(await C.run(root))); diff --git a/examples/rpc_call.ts b/examples/rpc_call.ts index 07d225ef3..bde845c0e 100644 --- a/examples/rpc_call.ts +++ b/examples/rpc_call.ts @@ -1,6 +1,6 @@ import * as C from "../mod.ts"; import * as U from "../util/mod.ts"; -const root = C.rpcCall(C.polkadot, "rpc_methods", []); +const root = new C.RpcCall(C.polkadot, "rpc_methods", []); -console.log(U.throwIfError(await root.run())); +console.log(U.throwIfError(await C.run(root))); diff --git a/examples/rpc_subscription.ts b/examples/rpc_subscription.ts index 28fd8050c..e4d853337 100644 --- a/examples/rpc_subscription.ts +++ b/examples/rpc_subscription.ts @@ -2,7 +2,7 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.rpcSubscription(T.polkadot, "chain_subscribeNewHead", [], (stop) => { +const root = new C.RpcSubscription(T.polkadot, "chain_subscribeNewHead", [], (stop) => { let i = 0; return (m) => { i++; @@ -13,4 +13,4 @@ const root = C.rpcSubscription(T.polkadot, "chain_subscribeNewHead", [], (stop) }; }); -U.throwIfError(await root.run()); +U.throwIfError(await C.run(root)); diff --git a/examples/those_of_subxt/read_bonded.ts b/examples/those_of_subxt/read_bonded.ts index 5ea1f99d8..81c5f55c3 100644 --- a/examples/those_of_subxt/read_bonded.ts +++ b/examples/those_of_subxt/read_bonded.ts @@ -4,6 +4,6 @@ import * as U from "../../util/mod.ts"; const aliceStash = T.alice.derive("//stash"); -const aliceBonded = C.readEntry(T.polkadot, "Staking", "Bonded", [aliceStash.publicKey]); +const aliceBonded = new C.EntryRead(T.polkadot, "Staking", "Bonded", [aliceStash.publicKey]); -console.log(U.throwIfError(await aliceBonded.run())); +console.log(U.throwIfError(await C.run(aliceBonded))); diff --git a/examples/those_of_subxt/read_era_rewards.ts b/examples/those_of_subxt/read_era_rewards.ts index 8ce05a802..c87c30573 100644 --- a/examples/those_of_subxt/read_era_rewards.ts +++ b/examples/those_of_subxt/read_era_rewards.ts @@ -1,10 +1,8 @@ import * as C from "../../mod.ts"; import * as U from "../../util/mod.ts"; -const idx = C.readEntry(C.polkadot, "Staking", "ActiveEra", []) - .select("value") - .select("index"); +const raw = new C.EntryRead(C.westend, "Staking", "ActiveEra", []); +const idx = C.sel(C.sel(raw, "value"), "index"); +const eraRewardPoints = new C.EntryRead(C.westend, "Staking", "ErasRewardPoints", [idx]); -const eraRewardPoints = C.readEntry(C.polkadot, "Staking", "ErasRewardPoints", [idx]); - -console.log(U.throwIfError(await eraRewardPoints.run())); +console.log(U.throwIfError(await C.run(eraRewardPoints))); diff --git a/examples/ticker.ts b/examples/ticker.ts index 10dc3f331..4b9514232 100644 --- a/examples/ticker.ts +++ b/examples/ticker.ts @@ -2,7 +2,7 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.watchEntry(T.polkadot, "Timestamp", "Now", [], (stop) => { +const root = new C.EntryWatch(T.polkadot, "Timestamp", "Now", [], (stop) => { let i = 0; return (m) => { i++; @@ -13,4 +13,4 @@ const root = C.watchEntry(T.polkadot, "Timestamp", "Now", [], (stop) => { }; }); -U.throwIfError(await root.run()); +U.throwIfError(await C.run(root)); diff --git a/examples/transfer.ts b/examples/transfer.ts index e8fbe9944..1aa6c32a5 100644 --- a/examples/transfer.ts +++ b/examples/transfer.ts @@ -2,8 +2,7 @@ import * as C from "../mod.ts"; import * as T from "../test_util/mod.ts"; import * as U from "../util/mod.ts"; -const root = C.sendAndWatchExtrinsic({ - config: T.westend, +const root = new C.ExtrinsicSentWatch(T.westend, { sender: { type: "Id", value: T.alice.publicKey, @@ -42,4 +41,4 @@ const root = C.sendAndWatchExtrinsic({ }, }); -U.throwIfError(await root.run()); +U.throwIfError(await C.run(root)); diff --git a/examples/watch_blocks.ts b/examples/watch_blocks.ts index 64f845563..29ae6d1c3 100644 --- a/examples/watch_blocks.ts +++ b/examples/watch_blocks.ts @@ -1,7 +1,7 @@ import * as C from "../mod.ts"; import * as U from "../util/mod.ts"; -const root = C.watchBlocks(C.westend, (stop) => { +const root = new C.BlockWatch(C.polkadot, (stop) => { let i = 0; return ({ block }) => { console.log(block.header); @@ -12,4 +12,4 @@ const root = C.watchBlocks(C.westend, (stop) => { }; }); -U.throwIfError(await root.run()); +U.throwIfError(await C.run(root)); diff --git a/examples/watch_blocks_iter.ts b/examples/watch_blocks_iter.ts index 50dbd8823..a083be502 100644 --- a/examples/watch_blocks_iter.ts +++ b/examples/watch_blocks_iter.ts @@ -7,7 +7,7 @@ import * as C from "../mod.ts"; const watchIter = C.watchIter(); -C.watchBlocks(C.rococo, watchIter).run(); +C.run(new C.BlockWatch(C.rococo, watchIter)); let i = 0; diff --git a/examples/watch_events.ts b/examples/watch_events.ts index 90cc042ec..4c5917c11 100644 --- a/examples/watch_events.ts +++ b/examples/watch_events.ts @@ -1,7 +1,7 @@ import * as C from "../mod.ts"; import * as U from "../util/mod.ts"; -const root = C.watchEntry(C.rococo, "System", "Events", [], (stop) => { +const root = new C.EntryWatch(C.rococo, "System", "Events", [], (stop) => { let i = 0; return (event) => { i++; @@ -12,4 +12,4 @@ const root = C.watchEntry(C.rococo, "System", "Events", [], (stop) => { }; }); -U.throwIfError(await root.run()); +U.throwIfError(await C.run(root)); diff --git a/mod.ts b/mod.ts index c5658c14c..413c52eff 100644 --- a/mod.ts +++ b/mod.ts @@ -1,6 +1,7 @@ export * from "./config/mod.ts"; export * as $ from "./deps/scale.ts"; export { BitSequence } from "./deps/scale.ts"; +export * from "./deps/zones.ts"; export * from "./effect/mod.ts"; export * as M from "./frame_metadata/mod.ts"; export { $era, $null, ChainError, type Era } from "./frame_metadata/mod.ts";