diff --git a/codegen/FrameCodegen.ts b/codegen/FrameCodegen.ts index f14a5738d..e52a9fd06 100644 --- a/codegen/FrameCodegen.ts +++ b/codegen/FrameCodegen.ts @@ -23,20 +23,19 @@ export class FrameCodegen { "chain.js", ` import * as _codecs from "./codecs.js" -import { connection } from "./connection.js" +import { connectionCtor, discoveryValue } from "./connection.js" import * as C from "./capi.js" import * as t from "./types/mod.js" export const metadata = ${this.codecCodegen.print(this.metadata)} -export const chain = C.Rune.rec({ metadata, connection }).into(C.ChainRune) +export const chain = C.ChainRune.from(connectionCtor, discoveryValue, metadata) `, ) files.set( "chain.d.ts", ` import * as _codecs from "./codecs.js" -import { connection } from "./connection.js" import * as C from "./capi.js" import * as t from "./types/mod.js" diff --git a/examples/dynamic.ts b/examples/dynamic.ts new file mode 100644 index 000000000..77947d700 --- /dev/null +++ b/examples/dynamic.ts @@ -0,0 +1,11 @@ +import { ChainRune, WsConnection } from "capi" + +const chain = ChainRune.from(WsConnection, "wss://rpc.polkadot.io") + +const accountInfo = await chain + .pallet("System") + .storage("Account") + .entryPage(10, null) + .run() + +console.log(accountInfo) diff --git a/examples/dynamic/balance.ts b/examples/dynamic/balance.ts deleted file mode 100644 index d66405164..000000000 --- a/examples/dynamic/balance.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { chain, users } from "polkadot_dev/mod.js" - -const [alexa] = await users(1) - -const result = await chain - .pallet("System") - .storage("Account") - .value(alexa.publicKey) - .run() - -console.log(result) diff --git a/fluent/ChainRune.ts b/fluent/ChainRune.ts index b8c34dac4..4ba1d7de3 100644 --- a/fluent/ChainRune.ts +++ b/fluent/ChainRune.ts @@ -1,6 +1,7 @@ +import { hex } from "../crypto/mod.ts" import * as $ from "../deps/scale.ts" -import { FrameMetadata } from "../frame_metadata/mod.ts" -import { Connection } from "../rpc/mod.ts" +import { decodeMetadata, FrameMetadata } from "../frame_metadata/mod.ts" +import { Connection, ConnectionCtorLike } from "../rpc/mod.ts" import { Rune, RunicArgs, ValueRune } from "../rune/mod.ts" import { BlockRune } from "./BlockRune.ts" import { ConnectionRune } from "./ConnectionRune.ts" @@ -50,6 +51,21 @@ export namespace Chain { // TODO: do we want to represent the discovery value and conn type within the type system? export class ChainRune extends Rune { + static from( + connectionCtor: ConnectionCtorLike, + discovery: D, + staticMetadata?: M, + ) { + const connection = ConnectionRune.from(async (signal) => + connectionCtor.connect(discovery, signal) + ) + const metadata = staticMetadata ?? Rune + .fn(hex.decode) + .call(connection.call("state_getMetadata")) + .map(decodeMetadata) + return Rune.rec({ connection, metadata }).into(this) + } + connection = this.into(ValueRune).access("connection").into(ConnectionRune) metadata = this.into(ValueRune).access("metadata") @@ -76,12 +92,11 @@ export class ChainRune extends Rune { return call.into(ExtrinsicRune, this.as(ChainRune)) } - pallet

, X>(...args: RunicArgs) { - const [palletName] = RunicArgs.resolve(args) - return this - .into(ValueRune) - .access("metadata", "pallets", palletName.as(Rune)) - .into(PalletRune, this) + pallet

, X>(...[palletName]: RunicArgs) { + return this.metadata + .access("pallets", palletName) + .unsafeAs>() + .into(PalletRune, this.as(ChainRune)) } addressPrefix(this: ChainRune) { diff --git a/fluent/ConnectionRune.ts b/fluent/ConnectionRune.ts index 355ff9c03..53046a9d1 100644 --- a/fluent/ConnectionRune.ts +++ b/fluent/ConnectionRune.ts @@ -13,11 +13,11 @@ class RunConnection extends Run { } } -export function connection(init: (signal: AbortSignal) => Promise) { - return Rune.new(RunConnection, init).into(ConnectionRune) -} - export class ConnectionRune extends Rune { + static from(init: (signal: AbortSignal) => Promise) { + return Rune.new(RunConnection, init).into(ConnectionRune) + } + call( callMethod: K, ...args: RunicArgs]> diff --git a/providers/frame/FrameProxyProvider.ts b/providers/frame/FrameProxyProvider.ts index 9c4ccfd54..cbe0cc4fa 100644 --- a/providers/frame/FrameProxyProvider.ts +++ b/providers/frame/FrameProxyProvider.ts @@ -66,13 +66,8 @@ export abstract class FrameProxyProvider extends FrameProvider { return ` import * as C from "./capi.js" +export const connectionCtor ${isTypes ? `: typeof C.WsConnection` : `= C.WsConnection`} export const discoveryValue ${isTypes ? ":" : "="} "${url}" - -export const connection ${ - isTypes - ? ": C.ConnectionRune" - : "= C.connection((signal) => C.WsConnection.connect(discoveryValue, signal))" - } ` } } diff --git a/rpc/Connection.ts b/rpc/Connection.ts index cfef44ef5..d10e94f6d 100644 --- a/rpc/Connection.ts +++ b/rpc/Connection.ts @@ -4,6 +4,11 @@ import { RpcCallMessage, RpcIngressMessage, RpcSubscriptionHandler } from "./rpc const connectionMemos = new Map Connection, Map>() +export interface ConnectionCtorLike { + new(discovery: D): Connection + connect: (discovery: D, signal: AbortSignal) => Connection +} + export abstract class Connection { nextId = 0 references = 0