From 4e38dec7f9cc4a4597f37caf3f1dba794afa3e85 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Sat, 19 Feb 2022 00:28:21 +0100 Subject: [PATCH] feat: wasm contracts intergration --- package.json | 1 + .../wasm-deploy-write-read.test.ts | 31 ++-- src/core/ContractDefinition.ts | 5 +- .../modules/impl/ContractDefinitionLoader.ts | 14 +- src/core/modules/impl/ContractHandlerApi.ts | 4 + .../modules/impl/DefaultStateEvaluator.ts | 2 + .../modules/impl/HandlerExecutorFactory.ts | 150 +++++++++++++++--- .../modules/impl/WasmContractHandlerApi.ts | 98 ++++++++++++ src/core/modules/impl/wasmImports.ts | 93 +++++++++++ src/legacy/smartweave-global.ts | 6 +- src/plugins/DebuggableExecutorFactor.ts | 4 +- src/utils/ArweaveWrapper.ts | 7 +- yarn.lock | 47 +++++- 13 files changed, 414 insertions(+), 48 deletions(-) create mode 100644 src/core/modules/impl/WasmContractHandlerApi.ts create mode 100644 src/core/modules/impl/wasmImports.ts diff --git a/package.json b/package.json index f8b0fc0..dec1cb9 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ }, "homepage": "https://github.com/redstone-finance/redstone-smartweave#readme", "dependencies": { + "@assemblyscript/loader": "^0.19.23", "@weavery/clarity": "^0.1.5", "arweave": "^1.10.16", "arweave-multihost": "^0.1.0", diff --git a/src/__tests__/integration/wasm-deploy-write-read.test.ts b/src/__tests__/integration/wasm-deploy-write-read.test.ts index 586e8c1..94b34f7 100644 --- a/src/__tests__/integration/wasm-deploy-write-read.test.ts +++ b/src/__tests__/integration/wasm-deploy-write-read.test.ts @@ -36,6 +36,7 @@ describe('Testing the SmartWeave client for WASM contract', () => { }); LoggerFactory.INST.logLevel('error'); + LoggerFactory.INST.logLevel('debug', 'WasmContractHandlerApi'); smartweave = SmartWeaveNodeFactory.memCached(arweave); @@ -62,35 +63,29 @@ describe('Testing the SmartWeave client for WASM contract', () => { await arlocal.stop(); }); - it('should properly deploy contract with initial state', async () => { + it('should properly deploy contract', async () => { const contractTx = await arweave.transactions.get(contractTxId); - expect(contractTx).not.toBeNull(); }); - - /* - it('should properly add new interaction', async () => { - await contract.writeInteraction({ function: 'add' }); - - await mineBlock(arweave); - - expect((await contract.readState()).state.counter).toEqual(556); + it('should properly read initial state', async () => { + expect((await contract.readState()).state.counter).toEqual(0); }); - it('should properly add another interactions', async () => { - await contract.writeInteraction({ function: 'add' }); + it('should properly read state after adding interactions', async () => { + await contract.writeInteraction({ function: 'increment' }); await mineBlock(arweave); - await contract.writeInteraction({ function: 'add' }); + await contract.writeInteraction({ function: 'increment' }); await mineBlock(arweave); - await contract.writeInteraction({ function: 'add' }); + await contract.writeInteraction({ function: 'increment' }); await mineBlock(arweave); - expect((await contract.readState()).state.counter).toEqual(559); + expect((await contract.readState()).state.counter).toEqual(3); }); it('should properly view contract state', async () => { - const interactionResult = await contract.viewState({ function: 'value' }); - expect(interactionResult.result).toEqual(559); - });*/ + const interactionResult = await contract.viewState({ function: 'fullName' }); + + expect(interactionResult.result.fullName).toEqual("first_ppe last_ppe"); + }); }); diff --git a/src/core/ContractDefinition.ts b/src/core/ContractDefinition.ts index 03c6198..dc02216 100644 --- a/src/core/ContractDefinition.ts +++ b/src/core/ContractDefinition.ts @@ -1,11 +1,14 @@ /** * This type contains all data and meta-data of the given contact. */ +import {ContractType} from "./modules/CreateContract"; + export type ContractDefinition = { txId: string; srcTxId: string; - src: string; + src: ArrayBuffer; initState: State; minFee: string; owner: string; + contractType: ContractType; }; diff --git a/src/core/modules/impl/ContractDefinitionLoader.ts b/src/core/modules/impl/ContractDefinitionLoader.ts index 53a0697..09ece16 100644 --- a/src/core/modules/impl/ContractDefinitionLoader.ts +++ b/src/core/modules/impl/ContractDefinitionLoader.ts @@ -2,6 +2,7 @@ import { ArweaveWrapper, Benchmark, ContractDefinition, + ContractType, DefinitionLoader, getTag, LoggerFactory, @@ -50,6 +51,10 @@ export class ContractDefinitionLoader implements DefinitionLoader { this.logger.debug('Tags decoding', benchmark.elapsed()); benchmark.reset(); + const contractSrcTx = await this.arweaveWrapper.tx(contractSrcTxId); + const contractType: ContractType = + getTag(contractSrcTx, SmartWeaveTags.CONTENT_TYPE) == 'application/javascript' ? 'js' : 'wasm'; + const src = await this.arweaveWrapper.txData(contractSrcTxId); this.logger.debug('Contract src tx load', benchmark.elapsed()); benchmark.reset(); @@ -63,18 +68,19 @@ export class ContractDefinitionLoader implements DefinitionLoader { src, initState, minFee, - owner + owner, + contractType }; } - private async evalInitialState(contractTx: Transaction) { + private async evalInitialState(contractTx: Transaction): Promise { if (getTag(contractTx, SmartWeaveTags.INIT_STATE)) { return getTag(contractTx, SmartWeaveTags.INIT_STATE); } else if (getTag(contractTx, SmartWeaveTags.INIT_STATE_TX)) { const stateTX = getTag(contractTx, SmartWeaveTags.INIT_STATE_TX); - return this.arweaveWrapper.txData(stateTX); + return this.arweaveWrapper.txDataString(stateTX); } else { - return this.arweaveWrapper.txData(contractTx.id); + return this.arweaveWrapper.txDataString(contractTx.id); } } } diff --git a/src/core/modules/impl/ContractHandlerApi.ts b/src/core/modules/impl/ContractHandlerApi.ts index 3dd86b6..7c0ac4a 100644 --- a/src/core/modules/impl/ContractHandlerApi.ts +++ b/src/core/modules/impl/ContractHandlerApi.ts @@ -219,4 +219,8 @@ export class ContractHandlerApi implements HandlerApi { return result?.cachedValue.state; }; } + + initState(state: State): void { + // nth to do in this impl... + } } diff --git a/src/core/modules/impl/DefaultStateEvaluator.ts b/src/core/modules/impl/DefaultStateEvaluator.ts index ae01c97..0f01de5 100644 --- a/src/core/modules/impl/DefaultStateEvaluator.ts +++ b/src/core/modules/impl/DefaultStateEvaluator.ts @@ -61,6 +61,8 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { let currentState = baseState.state; const validity = baseState.validity; + executionContext.handler.initState(currentState); + this.logger.info( `Evaluating state for ${contractDefinition.txId} [${missingInteractions.length} non-cached of ${sortedInteractions.length} all]` ); diff --git a/src/core/modules/impl/HandlerExecutorFactory.ts b/src/core/modules/impl/HandlerExecutorFactory.ts index 1f59142..2cc873b 100644 --- a/src/core/modules/impl/HandlerExecutorFactory.ts +++ b/src/core/modules/impl/HandlerExecutorFactory.ts @@ -10,6 +10,134 @@ import { SmartWeaveGlobal } from '@smartweave'; import { ContractHandlerApi } from './ContractHandlerApi'; +import loader from '@assemblyscript/loader/umd'; +import { imports } from './wasmImports'; +import { WasmContractHandlerApi } from './WasmContractHandlerApi'; + +/** + * A factory that produces handlers that are compatible with the "current" style of + * writing SW contracts (ie. using "handle" function). + */ +export class HandlerExecutorFactory implements ExecutorFactory> { + private readonly logger = LoggerFactory.INST.create('HandlerExecutorFactory'); + + constructor(private readonly arweave: Arweave) {} + + async create(contractDefinition: ContractDefinition): Promise> { + const swGlobal = new SmartWeaveGlobal(this.arweave, { + id: contractDefinition.txId, + owner: contractDefinition.owner + }); + + if (contractDefinition.contractType == 'js') { + const normalizedSource = normalizeContractSource(this.arweave.utils.bufferToString(contractDefinition.src)); + + const contractFunction = new Function(normalizedSource); + + return new ContractHandlerApi(swGlobal, contractFunction, contractDefinition); + } else { + let wasmExports; + + const wasmModule = loader.instantiateSync(contractDefinition.src, { + metering: { + usegas: (gas) => { + if (gas < 0) { + return; + } + swGlobal.gasUsed += gas; + if (swGlobal.gasUsed > swGlobal.gasLimit) { + throw new Error( + `[RE:OOG] Out of gas! Limit: ${formatGas(swGlobal.gasUsed)}, used: ${formatGas(swGlobal.gasLimit)}` + ); + } + } + }, + console: { + 'console.log': function (msgPtr) { + console.log(`Contract: ${wasmExports.__getString(msgPtr)}`); + }, + 'console.logO': function (msgPtr, objPtr) { + console.log(`Contract: ${wasmExports.__getString(msgPtr)}`, JSON.parse(wasmExports.__getString(objPtr))); + } + }, + block: { + 'Block.height': function () { + return 875290; + }, + 'Block.indep_hash': function () { + return wasmExports.__newString('iIMsQJ1819NtkEUEMBRl6-7I6xkeDipn1tK4w_cDFczRuD91oAZx5qlgSDcqq1J1'); + }, + 'Block.timestamp': function () { + return 123123123; + } + }, + transaction: { + 'Transaction.id': function () { + return wasmExports.__newString('Transaction.id'); + }, + 'Transaction.owner': function () { + return wasmExports.__newString('Transaction.owner'); + }, + 'Transaction.target': function () { + return wasmExports.__newString('Transaction.target'); + } + }, + contract: { + 'Contract.id': function () { + return wasmExports.__newString('Contract.id'); + }, + 'Contract.owner': function () { + return wasmExports.__newString('Contract.owner'); + } + }, + msg: { + 'msg.sender': function () { + return wasmExports.__newString('msg.sender'); + } + }, + api: { + _readContractState: (fnIndex, contractTxIdPtr) => { + const contractTxId = wasmExports.__getString(contractTxIdPtr); + const callbackFn = getFn(fnIndex); + console.log('Simulating read state of', contractTxId); + return setTimeout(() => { + console.log('calling callback'); + callbackFn( + wasmExports.__newString( + JSON.stringify({ + contractTxId + }) + ) + ); + }, 1000); + }, + clearTimeout + }, + env: { + abort(messagePtr, fileNamePtr, line, column) { + console.error('--------------------- Error message from AssemblyScript ----------------------'); + console.error(' ' + wasmExports.__getString(messagePtr)); + console.error(' In file "' + wasmExports.__getString(fileNamePtr) + '"'); + console.error(` on line ${line}, column ${column}.`); + console.error('------------------------------------------------------------------------------\n'); + } + } + }); + + function getFn(idx) { + return wasmExports.table.get(idx); + } + + function formatGas(gas) { + return gas * 1e-4; + } + + wasmExports = wasmModule.exports; + + return new WasmContractHandlerApi(swGlobal, contractDefinition, wasmExports); + } + } +} export interface InteractionData { interaction?: ContractInteraction; @@ -26,28 +154,8 @@ export interface HandlerApi { currentResult: EvalStateResult, interactionData: InteractionData ): Promise>; -} -/** - * A factory that produces handlers that are compatible with the "current" style of - * writing SW contracts (ie. using "handle" function). - */ -export class HandlerExecutorFactory implements ExecutorFactory> { - private readonly logger = LoggerFactory.INST.create('HandlerExecutorFactory'); - - constructor(private readonly arweave: Arweave) {} - - async create(contractDefinition: ContractDefinition): Promise> { - const normalizedSource = normalizeContractSource(contractDefinition.src); - - const swGlobal = new SmartWeaveGlobal(this.arweave, { - id: contractDefinition.txId, - owner: contractDefinition.owner - }); - const contractFunction = new Function(normalizedSource); - - return new ContractHandlerApi(swGlobal, contractFunction, contractDefinition); - } + initState(state: State): void; } export type HandlerFunction = ( diff --git a/src/core/modules/impl/WasmContractHandlerApi.ts b/src/core/modules/impl/WasmContractHandlerApi.ts new file mode 100644 index 0000000..d6c22c9 --- /dev/null +++ b/src/core/modules/impl/WasmContractHandlerApi.ts @@ -0,0 +1,98 @@ +/* eslint-disable */ +import { + ContractDefinition, + EvalStateResult, + ExecutionContext, + HandlerApi, + InteractionData, + InteractionResult, + LoggerFactory, + RedStoneLogger, + SmartWeaveGlobal +} from '@smartweave'; +import stringify from "safe-stable-stringify"; + +export class WasmContractHandlerApi implements HandlerApi { + private readonly contractLogger: RedStoneLogger; + private readonly logger = LoggerFactory.INST.create('WasmContractHandlerApi'); + + constructor( + private readonly swGlobal: SmartWeaveGlobal, + private readonly contractDefinition: ContractDefinition, + private readonly wasmExports: any + ) { + this.contractLogger = LoggerFactory.INST.create(swGlobal.contract.id); + } + + initState(state: State): void { + const statePtr = this.wasmExports.__newString(stringify(state)); + this.wasmExports.initState(statePtr); + } + + async handle( + executionContext: ExecutionContext, + currentResult: EvalStateResult, + interactionData: InteractionData + ): Promise> { + const contractLogger = LoggerFactory.INST.create('Contract'); + + + try { + const {interaction, interactionTx, currentTx} = interactionData; + + this.swGlobal._activeTx = interactionTx; + + const handlerResult = this.doHandle(interaction); + + return { + type: 'ok', + result: handlerResult, + state: this.doGetCurrentState() + }; + } catch (e) { + // note: as exceptions handling in WASM is currently somewhat non-existent + // https://www.assemblyscript.org/status.html#exceptions + // and since we have to somehow differentiate different types of exceptions + // - each exception message has to have a proper prefix added. + + // exceptions with prefix [RE:] ("Runtime Exceptions") should break the execution immediately + // - eg: [RE:OOG] - [RuntimeException: OutOfGas] + + // exception with prefix [CE:] ("Contract Exceptions") should be logged, but should not break + // the state evaluation - as they are considered as contracts' business exception (eg. validation errors) + // - eg: [CE:WTF] - [ContractException: WhatTheFunction] ;-) + if (e.message.startsWith('[RE:')) { + return { + type: 'exception', + errorMessage: e.message, + state: currentResult.state, + result: null + }; + } else { + return { + type: 'error', + errorMessage: e.message, + state: currentResult.state, + result: null + }; + } + } + } + + private doHandle(action: any): any { + this.logger.info("Action", action.input); + const actionPtr = this.wasmExports.__newString(stringify(action.input)); + const resultPtr = this.wasmExports.handle(actionPtr); + const result = this.wasmExports.__getString(resultPtr); + + this.logger.info("Result", result); + this.logger.info("State", this.doGetCurrentState()); + + return JSON.parse(result); + } + + private doGetCurrentState(): State { + const currentStatePtr = this.wasmExports.currentState(); + return JSON.parse(this.wasmExports.__getString(currentStatePtr)); + } +} diff --git a/src/core/modules/impl/wasmImports.ts b/src/core/modules/impl/wasmImports.ts new file mode 100644 index 0000000..4cd3aff --- /dev/null +++ b/src/core/modules/impl/wasmImports.ts @@ -0,0 +1,93 @@ +import {SmartWeaveGlobal} from "@smartweave"; + +export function imports(swGlobal: SmartWeaveGlobal, wasmExports: any): any { + return { + metering: { + usegas: (gas) => { + if (gas < 0) { + return; + } + swGlobal.gasUsed += gas; + if (swGlobal.gasUsed > swGlobal.gasLimit) { + throw new Error(`[RE:OOG] Out of gas! Limit: ${formatGas(swGlobal.gasUsed)}, used: ${formatGas(swGlobal.gasLimit)}`); + } + } + }, + console: { + "console.log": function (msgPtr) { + console.log(`Contract: ${wasmExports.__getString(msgPtr)}`); + }, + "console.logO": function (msgPtr, objPtr) { + console.log(`Contract: ${wasmExports.__getString(msgPtr)}`, JSON.parse(wasmExports.__getString(objPtr))); + }, + }, + block: { + "Block.height": function () { + return 875290; + }, + "Block.indep_hash": function () { + return wasmExports.__newString("iIMsQJ1819NtkEUEMBRl6-7I6xkeDipn1tK4w_cDFczRuD91oAZx5qlgSDcqq1J1"); + }, + "Block.timestamp": function () { + return 123123123; + }, + }, + transaction: { + "Transaction.id": function () { + return wasmExports.__newString("Transaction.id"); + }, + "Transaction.owner": function () { + return wasmExports.__newString("Transaction.owner"); + }, + "Transaction.target": function () { + return wasmExports.__newString("Transaction.target"); + }, + }, + contract: { + "Contract.id": function () { + return wasmExports.__newString("Contract.id"); + }, + "Contract.owner": function () { + return wasmExports.__newString("Contract.owner"); + }, + }, + msg: { + "msg.sender": function () { + return wasmExports.__newString("msg.sender"); + }, + }, + api: { + _readContractState: (fnIndex, contractTxIdPtr) => { + const contractTxId = wasmExports.__getString(contractTxIdPtr); + const callbackFn = getFn(fnIndex); + console.log("Simulating read state of", contractTxId); + return setTimeout(() => { + console.log('calling callback'); + callbackFn(wasmExports.__newString(JSON.stringify({ + contractTxId + }))); + }, 1000); + }, + clearTimeout, + }, + env: { + abort(messagePtr, fileNamePtr, line, column) { + console.error("--------------------- Error message from AssemblyScript ----------------------"); + console.error(" " + wasmExports.__getString(messagePtr)); + console.error( + ' In file "' + wasmExports.__getString(fileNamePtr) + '"' + ); + console.error(` on line ${line}, column ${column}.`); + console.error("------------------------------------------------------------------------------\n"); + }, + } + } + + function getFn(idx) { + return wasmExports.table.get(idx); + } +} + +function formatGas(gas) { + return gas * 1e-4; +} diff --git a/src/legacy/smartweave-global.ts b/src/legacy/smartweave-global.ts index 39e081d..8225da5 100644 --- a/src/legacy/smartweave-global.ts +++ b/src/legacy/smartweave-global.ts @@ -28,6 +28,8 @@ import { GQLNodeInterface, GQLTagInterface } from './gqlResult'; * */ export class SmartWeaveGlobal { + gasUsed: number; + gasLimit: number; transaction: Transaction; block: Block; arweave: Pick; @@ -46,7 +48,9 @@ export class SmartWeaveGlobal { _activeTx?: GQLNodeInterface; - constructor(arweave: Arweave, contract: { id: string; owner: string }) { + constructor(arweave: Arweave, contract: { id: string; owner: string }, gasLimit = Number.MAX_SAFE_INTEGER) { + this.gasUsed = 0; + this.gasLimit = gasLimit; this.unsafeClient = arweave; this.arweave = { ar: arweave.ar, diff --git a/src/plugins/DebuggableExecutorFactor.ts b/src/plugins/DebuggableExecutorFactor.ts index 9c6aed3..e97e0b4 100644 --- a/src/plugins/DebuggableExecutorFactor.ts +++ b/src/plugins/DebuggableExecutorFactor.ts @@ -16,9 +16,11 @@ export class DebuggableExecutorFactory implements ExecutorFactory { async create(contractDefinition: ContractDefinition): Promise { if (Object.prototype.hasOwnProperty.call(this.sourceCode, contractDefinition.txId)) { + const enc = new TextEncoder(); // always utf-8 + contractDefinition = { ...contractDefinition, - src: this.sourceCode[contractDefinition.txId] + src: enc.encode(this.sourceCode[contractDefinition.txId]) }; } diff --git a/src/utils/ArweaveWrapper.ts b/src/utils/ArweaveWrapper.ts index ae5ef03..4cd64d0 100644 --- a/src/utils/ArweaveWrapper.ts +++ b/src/utils/ArweaveWrapper.ts @@ -88,12 +88,17 @@ export class ArweaveWrapper { }); } - async txData(id: string): Promise { + async txData(id: string): Promise { const response = await fetch(`${this.baseUrl}/${id}`); if (!response.ok) { throw new Error(`Unable to load tx data ${id}`); } const buffer = await response.arrayBuffer(); + return buffer; + } + + async txDataString(id: string): Promise { + const buffer = await this.txData(id); return Arweave.utils.bufferToString(buffer); } } diff --git a/yarn.lock b/yarn.lock index 830dc02..3d5083f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,6 +51,11 @@ http-errors "^1.7.3" object-path "^0.11.4" +"@assemblyscript/loader@^0.19.23": + version "0.19.23" + resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.19.23.tgz#7fccae28d0a2692869f1d1219d36093bc24d5e72" + integrity sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw== + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" @@ -1769,7 +1774,7 @@ bluebird@^2.6.2, bluebird@^2.8.1: resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz" integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= -bn.js@^4.0.0, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -1862,6 +1867,20 @@ buffer-from@^1.0.0: resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer-pipe@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/buffer-pipe/-/buffer-pipe-0.0.0.tgz#186ec257d696e8e74c3051160a0e9e9a9811a387" + integrity sha512-PvKbsvQOH4dcUyUEvQQSs3CIkkuPcOHt3gKnXwf4HsPKFDxSN7bkmICVIWgOmW/jx/fAEGGn4mIayIJPLs7G8g== + dependencies: + safe-buffer "^5.1.1" + +buffer-pipe@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/buffer-pipe/-/buffer-pipe-0.0.2.tgz#960678ab517ca926dc1bfe231f402cbe2fe74442" + integrity sha512-YlqzbWVqMv+xEeRyg0OXAJym3zAFTAIuku9l7okwxOXNDxbmSlL5o3QaF5k6IQ2iHO9o1OCo6tT4UkrQkI5VbQ== + dependencies: + safe-buffer "^5.1.1" + buffer-writer@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz" @@ -4693,6 +4712,14 @@ koa@^2.13.1: type-is "^1.6.16" vary "^1.1.2" +leb128@0.0.4, leb128@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/leb128/-/leb128-0.0.4.tgz#f96d698cf3ba5b677423abfe50b7e9b2df1463ff" + integrity sha512-2zejk0fCIgY8RVcc/KzvyfpDio5Oo8HgPZmkrOmdwmbk0KpKpgD+JKwikxKk8cZYkANIhwHK50SNukkCm3XkCQ== + dependencies: + bn.js "^4.11.6" + buffer-pipe "0.0.0" + leven@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" @@ -6760,6 +6787,24 @@ walker@^1.0.7: dependencies: makeerror "1.0.12" +wasm-json-toolkit@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/wasm-json-toolkit/-/wasm-json-toolkit-0.2.3.tgz#51207da907a343152b02d0e97ee30c4a6e9f2308" + integrity sha512-W0pESOST9hHFEmHq9kzMxAEhcPYuASdYCDw4FavKSyQKh3uOmH2slRXR/MhTKJY+gp1AauUDNd9DeE0cS4bV4A== + dependencies: + bn.js "^4.11.8" + buffer-pipe "0.0.2" + leb128 "0.0.4" + safe-buffer "^5.1.1" + +wasm-metering@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/wasm-metering/-/wasm-metering-0.2.1.tgz#08220896e5e74b4ee3286636fd31d84e40544083" + integrity sha512-YDlTPY4jspknNyDaVBQhLTuTYBh+39qI0P9F0grmR88NR4oh7qfgpTwZ2ly4oX2hHCj9KlIwhy2Yyez+3/wY2Q== + dependencies: + leb128 "^0.0.4" + wasm-json-toolkit "0.2.3" + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz"