Skip to content
This repository has been archived by the owner on Sep 14, 2023. It is now read-only.

Commit

Permalink
pairing with t6
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay committed Jan 31, 2023
1 parent b27d058 commit f77df0b
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 64 deletions.
2 changes: 1 addition & 1 deletion examples/batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ await Utility.batchAll({
})
.signed({ sender: alice })
.sent()
.logEvents()
.logStatus()
.finalized()
.unwrapError()
.run()
Expand Down
55 changes: 28 additions & 27 deletions examples/ink_contract/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,39 @@ const contract = client.inkContract({
metadataRaw: Deno.readTextFileSync("examples/ink_contract/metadata.json"),
})

const instance = contract
await contract
.instantiate({
code: Deno.readFileSync("examples/ink_contract/flipper.wasm"),
initiator: alice.publicKey,
})
.signed({ sender: alice })
.sent()
.logEvents()
.instance()
.logStatus()
.inBlock()
.run()

// TODO: what values do we want?
console.log(".get", await instance.msg("get").run())
console.log(".flip", await instance.msg("flip").signed({ sender: alice }).run())
console.log(".get", await instance.msg("get").run())
console.log(".get_count", await instance.msg("get_count").run())
console.log(".inc", await instance.msg("inc").signed({ sender: alice }).run())
console.log(".inc", await instance.msg("inc").signed({ sender: alice }).run())
console.log(".get_count", await instance.msg("get_count").signed({ sender: alice }).run())
console.log(
".inc_by(3)",
await instance.msg("inc_by", 3).signed({ sender: alice }).run(),
)
console.log(".get_count", await instance.msg("get_count").run())
console.log(
".inc_by_with_event(3) contract events",
await instance.msg("inc_by_with_event", 3).signed({ sender: alice }).run(),
)
console.log(
".method_returning_tuple(2,true)",
await instance.msg("method_returning_tuple", 2, true).signed({ sender: alice }).run(),
)
console.log(
".method_returning_struct(3,false)",
await instance.msg("method_returning_struct", 3, false).signed({ sender: alice }).run(),
)
// console.log(".get", await instance.msg("get").run())
// console.log(".flip", await instance.msg("flip").signed({ sender: alice }).run())
// console.log(".get", await instance.msg("get").run())
// console.log(".get_count", await instance.msg("get_count").run())
// console.log(".inc", await instance.msg("inc").signed({ sender: alice }).run())
// console.log(".inc", await instance.msg("inc").signed({ sender: alice }).run())
// console.log(".get_count", await instance.msg("get_count").signed({ sender: alice }).run())
// console.log(
// ".inc_by(3)",
// await instance.msg("inc_by", 3).signed({ sender: alice }).run(),
// )
// console.log(".get_count", await instance.msg("get_count").run())
// console.log(
// ".inc_by_with_event(3) contract events",
// await instance.msg("inc_by_with_event", 3).signed({ sender: alice }).run(),
// )
// console.log(
// ".method_returning_tuple(2,true)",
// await instance.msg("method_returning_tuple", 2, true).signed({ sender: alice }).run(),
// )
// console.log(
// ".method_returning_struct(3,false)",
// await instance.msg("method_returning_struct", 3, false).signed({ sender: alice }).run(),
// )
2 changes: 1 addition & 1 deletion examples/polkadot_js_signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ await Balances
},
})
.sent()
.logEvents()
.logStatus()
.finalized()
.run()
8 changes: 5 additions & 3 deletions examples/transfer.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as C from "capi/mod.ts"
import { Balances } from "westend_dev/mod.ts"

await Balances.transfer({
const x = await Balances.transfer({
value: 12345n,
dest: C.bob.address,
})
.signed({ sender: C.alice })
.sent()
.logEvents()
.finalized()
.logStatus()
.events()
.run()

console.log(x)
14 changes: 6 additions & 8 deletions fluent/InkContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export class InkContractRune<out U> extends Rune<InkContract, U> {
.unwrapError()
}

salt() {
return crypto.getRandomValues(new Uint8Array(4))
}

// TODO: create instantiation-specific rune so that we can `.address()` from it
instantiate<X>(props: RunicArgs<X, InkContractInstantiateProps>) {
const ctor = this.ctor(props.ctor)
Expand All @@ -61,7 +65,7 @@ export class InkContractRune<out U> extends Rune<InkContract, U> {
undefined,
{ type: "Upload", value: code },
U.hex.decode(ctor.selector),
SALT,
this.salt(),
]))
)
const gasRequired = state
Expand All @@ -73,9 +77,6 @@ export class InkContractRune<out U> extends Rune<InkContract, U> {
return this.client.extrinsic(
Rune
.tuple([props.code, ctor, gasRequired])
.unwrapError()
.unwrapNull()
.unwrapUndefined()
.map(([code, ctor, gasRequired]) => ({
type: "Contracts",
value: {
Expand All @@ -85,7 +86,7 @@ export class InkContractRune<out U> extends Rune<InkContract, U> {
storageDepositLimit: undefined,
code,
data: U.hex.decode(ctor.selector),
salt: SALT,
salt: this.salt(),
},
})),
)
Expand Down Expand Up @@ -132,6 +133,3 @@ export class InkContractMsgSigned<out U> extends Rune<Uint8Array, U> {
export class InkContractMetadataInvalidError extends Error {
override readonly name = "InkContractMetadataInvalidError"
}

// TODO: how is this determined?
const SALT = Uint8Array.from(Array.from([0, 0, 0, 0]), () => Math.floor(Math.random() * 16))
15 changes: 10 additions & 5 deletions fluent/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import { Multisig, MultisigRune } from "./multisig.ts"
import { rpcCall } from "./rpc.ts"
import { state } from "./rpc_known_methods.ts"

export class ClientRune<out U, out Call = unknown> extends Rune<rpc.Client, U> {
export interface Chain {
call: unknown
event: unknown
}

export class ClientRune<out U, out C extends Chain = Chain> extends Rune<rpc.Client, U> {
metadata<X>(...[blockHash]: RunicArgs<X, [blockHash?: HexHash]>) {
return state
.getMetadata(this.as(), blockHash)
Expand All @@ -26,9 +31,9 @@ export class ClientRune<out U, out Call = unknown> extends Rune<rpc.Client, U> {
.as(MetadataRune, this)
}

extrinsic<X>(...args: RunicArgs<X, [call: Call]>) {
extrinsic<X>(...args: RunicArgs<X, [call: C["call"]]>) {
const [call] = RunicArgs.resolve(args)
return call.as(ExtrinsicRune<Call, RunicArgs.U<X> | U>, this)
return call.as(ExtrinsicRune<RunicArgs.U<X> | U, C>, this)
}

multisig<X>(...args: RunicArgs<X, [multisig: Multisig]>) {
Expand All @@ -43,7 +48,7 @@ export class ClientRune<out U, out Call = unknown> extends Rune<rpc.Client, U> {

chainVersion = rpcCall<[], string>("system_version")(this.as()).unwrapError()

private _asCodegen<Call>() {
return this as any as ClientRune<U, Call>
private _asCodegen<C extends Chain>() {
return this as any as ClientRune<U, C>
}
}
68 changes: 59 additions & 9 deletions fluent/extrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { MetaRune, Rune, RunicArgs, ValueRune } from "../rune/mod.ts"
import { Era, era } from "../scale_info/mod.ts"
import { Blake2_256 } from "../util/hashers.ts"
import * as U from "../util/mod.ts"
import { ClientRune } from "./client.ts"
import { Hex } from "../util/mod.ts"
import { Chain, ClientRune } from "./client.ts"
import { CodecRune } from "./codec.ts"
import { author, chain, payment, system } from "./rpc_known_methods.ts"

Expand All @@ -22,8 +23,8 @@ export interface SignedExtrinsicProps {
tip?: bigint
}

export class ExtrinsicRune<out Call, out U> extends Rune<Call, U> {
constructor(_prime: ExtrinsicRune<Call, U>["_prime"], readonly client: ClientRune<U>) {
export class ExtrinsicRune<out U, out C extends Chain = Chain> extends Rune<C["call"], U> {
constructor(_prime: ExtrinsicRune<U, C>["_prime"], readonly client: ClientRune<U, Chain>) {
super(_prime)
}

Expand Down Expand Up @@ -116,7 +117,7 @@ export class ExtrinsicRune<out Call, out U> extends Rune<Call, U> {
}
}

export class SignedExtrinsicRune<out U> extends Rune<Uint8Array, U> {
export class SignedExtrinsicRune<out U, out C extends Chain = Chain> extends Rune<Uint8Array, U> {
constructor(_prime: SignedExtrinsicRune<U>["_prime"], readonly client: ClientRune<U>) {
super(_prime)
}
Expand All @@ -129,22 +130,27 @@ export class SignedExtrinsicRune<out U> extends Rune<Uint8Array, U> {
return this.hex().map((hex) =>
author.submitAndWatchExtrinsic(this.client as ClientRune<never>, hex)
.unwrapError()
).as(ExtrinsicStatusRune)
).as(ExtrinsicStatusRune, this)
}
}

export class ExtrinsicStatusRune<out U1, out U2> extends Rune<Rune<TransactionStatus, U1>, U2> {
constructor(_prime: ExtrinsicStatusRune<U1, U2>["_prime"]) {
export class ExtrinsicStatusRune<out U1, out U2, out C extends Chain = Chain>
extends Rune<Rune<TransactionStatus, U1>, U2>
{
constructor(
_prime: ExtrinsicStatusRune<U1, U2, C>["_prime"],
readonly extrinsic: SignedExtrinsicRune<U2>,
) {
super(_prime)
}

logEvents(...prefix: unknown[]): ExtrinsicStatusRune<U1, U2> {
logStatus(...prefix: unknown[]): ExtrinsicStatusRune<U1, U2, C> {
return this.as(ValueRune).map((rune) =>
rune.as(ValueRune).map((value) => {
console.log(...prefix, value)
return value
})
).as(ExtrinsicStatusRune)
).as(ExtrinsicStatusRune<U1, U2, C>, this.extrinsic)
}

// TODO: extract common logic to be shared between `inBlock` and `finalized`
Expand Down Expand Up @@ -176,6 +182,50 @@ export class ExtrinsicStatusRune<out U1, out U2> extends Rune<Rune<TransactionSt
.singular()
).unwrapError()
}

events() {
const finalizedHash = this.finalized()
const extrinsics = chain
.getBlock(this.extrinsic.client, finalizedHash)
.unwrapError()
.access("block", "extrinsics")
const idx = Rune.tuple([extrinsics, this.extrinsic.hex()])
.map(([extrinsics, extrinsicHex]) => extrinsics.indexOf(("0x" + extrinsicHex) as Hex))
const events = this.extrinsic.client
.metadata()
.pallet("System")
.storage("Events")
.entry([], finalizedHash)
.unsafeAs<Events<C["event"]>>()
.as(ValueRune)
return Rune.tuple([idx, events])
.map(([idx, events]) =>
events.filter((event) => event.phase.type === "ApplyExtrinsic" && event.phase.value === idx)
)
}
}

export type Events<RuntimeEvent = unknown> = EventRecord<RuntimeEvent>[]
export interface EventRecord<RuntimeEvent> {
phase: EventPhase
event: RuntimeEvent
topics: Uint8Array[]
}
export type EventPhase =
| EventPhase.ApplyExtrinsic
| EventPhase.Finalization
| EventPhase.Initialization
export namespace EventPhase {
export interface ApplyExtrinsic {
type: "ApplyExtrinsic"
value: number
}
export interface Finalization {
type: "Finalization"
}
export interface Initialization {
type: "Initialization"
}
}

export class NeverInBlockError extends Error {}
Expand Down
4 changes: 2 additions & 2 deletions rune/MetaRune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class RunFlat<T, U1, U2> extends Run<T, U1 | U2> {
if (receipt.novel) {
this.innerController.abort()
this.innerController = new AbortController()
const innerBatch = new Batch(this.batch.timeline, this.batch)
this.currentInner = innerBatch.prime(rune, this.innerController.signal)
// const innerBatch = new Batch(this.batch.timeline, this.batch)
this.currentInner = this.batch.prime(rune, this.innerController.signal)
}
const _receipt = new Receipt()
try {
Expand Down
16 changes: 12 additions & 4 deletions rune/Rune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,24 @@ export class Batch {
readonly wrapParent: <T, U>(rune: Run<T, U>) => Run<T, U> = (x) => x,
) {}

primed = new Map<Rune<any, any>, Run<any, any>>()
primed = new Map<Rune<any, any>["_prime"], Run<any, any>>()
prime<T, E>(rune: Rune<T, E>, signal: AbortSignal): Run<T, E> {
const primed = getOrInit(this.primed, rune, () => this.getPrimed(rune) ?? rune._prime(this))
const primed = getOrInit(
this.primed,
rune._prime,
() => this.getPrimed(rune) ?? rune._prime(this),
)
primed.reference(signal)
return primed
}

getPrimed<T, E>(rune: Rune<T, E>): Run<T, E> | undefined {
const existing = this.primed.get(rune)
const existing = this.primed.get(rune._prime)
if (existing) return existing
const parent = this.parent?.getPrimed(rune)
if (parent) {
const wrapped = this.wrapParent(parent)
this.primed.set(rune, wrapped)
this.primed.set(rune._prime, wrapped)
return wrapped
}
return undefined
Expand Down Expand Up @@ -140,6 +144,10 @@ export class Rune<out T, out U = never> {
) {
return new ctor(this._prime as any, ...args)
}

pipe<R extends Rune<any, any>>(fn: (rune: this) => R): R {
return fn(this)
}
}

export abstract class Run<T, U> {
Expand Down
4 changes: 0 additions & 4 deletions rune/ValueRune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ export class ValueRune<out T, out U = never> extends Rune<T, U> {
return new ValueRune((batch) => new ctor(batch, ...args))
}

pipe<R extends Rune<any, any>>(fn: (rune: this) => R): R {
return fn(this)
}

map<T2>(fn: (value: T) => PromiseOr<T2>): ValueRune<T2, U> {
return ValueRune.new(RunMap, this, fn)
}
Expand Down

0 comments on commit f77df0b

Please sign in to comment.