import "../../../_dnt.polyfills.js"; import { ArrayRune, Chain, CodecRune, Event, ExtrinsicRune, hex, is, PatternRune, Rune, RunicArgs, ValueRune, } from "../../../mod.js" import { $contractsApiCallArgs, $contractsApiCallResult, Weight } from "./codecs.js" import { isContractEmitted } from "./events.js" import { InkMetadataRune } from "./InkMetadataRune.js" export interface MsgProps { sender: Uint8Array method: string args?: unknown[] value?: bigint gasLimit?: Weight } export class InkRune extends PatternRune> { innerCall(...args_: RunicArgs) { const [sender, value, data] = RunicArgs.resolve(args_) const instantiateArgs = Rune .constant($contractsApiCallArgs) .into(CodecRune) .encoded(Rune.tuple([sender, this, value, undefined, undefined, data])) return this.chain.connection .call("state_call", "ContractsApi_call", instantiateArgs.map(hex.encode)) .map((result) => $contractsApiCallResult.decode(hex.decode(result))) } common(this: InkRune, props: RunicArgs) { const msgMetadata = Rune .tuple([ this.parent.into(ValueRune).access("spec", "messages"), props.method, ]) .map(([msgs, methodName]) => msgs.find((msgs) => msgs.label === methodName)) .unhandle(is(undefined)) .rehandle(is(undefined), () => Rune.constant(new MethodNotFoundError())) .unhandle(is(MethodNotFoundError)) const data = this.parent.encodeData(msgMetadata, props.args) const value = Rune .resolve(props.value) .handle(is(undefined), () => Rune.constant(0n)) const innerResult = this.innerCall(props.sender, value, data) return { msgMetadata, data, value, innerResult } } call(props: RunicArgs) { const { msgMetadata, innerResult } = this.common(props) const $result = this.parent.codecs .access(msgMetadata.access("returnType", "type")) .into(CodecRune) return $result.decoded(innerResult.access("result", "data")) } tx(props: RunicArgs) { const { value, data, innerResult } = this.common(props) const gasLimit = innerResult.access("gasRequired") // TODO: make explicitly configurable? const storageDepositLimit = innerResult.access("storageDeposit", "value") return Rune .object({ type: "Contracts", value: Rune.object({ type: "call", dest: Rune.object({ type: "Id", value: this.as(InkRune), }), value, data, gasLimit, storageDepositLimit, }), }) .unsafeAs>() .into(ExtrinsicRune, this.chain) } emittedEvents = (...[events]: RunicArgs) => { return Rune .resolve(events) .map((events) => events.filter(isContractEmitted)) .into(ArrayRune) .mapArray((event) => this.parent.$event.decoded(event.access("event", "value", "data"))) } } export class MethodNotFoundError extends Error { override readonly name = "MethodNotFoundError" }