From fc62cf6d8dda34ab22e2266c1fde6b756a2bd70c Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 8 Apr 2024 13:30:26 +0200 Subject: [PATCH] fix lint --- evm/evm-codec/.prettierrc | 7 + evm/evm-codec/package.json | 3 +- evm/evm-codec/src/abi-components/event.ts | 50 ++-- evm/evm-codec/src/abi-components/function.ts | 86 +++---- evm/evm-codec/src/codec.ts | 24 +- evm/evm-codec/src/codecs/array.ts | 72 +++--- evm/evm-codec/src/codecs/primitives.ts | 220 +++++++++--------- evm/evm-codec/src/codecs/struct.ts | 70 +++--- evm/evm-codec/src/contract-base.ts | 68 +++--- evm/evm-codec/src/index.ts | 10 +- evm/evm-codec/src/sink.ts | 209 ++++++++--------- evm/evm-codec/src/src.ts | 150 ++++++------ evm/evm-codec/src/utils.ts | 28 ++- evm/evm-codec/test/array.test.ts | 230 +++++++++---------- evm/evm-codec/test/event.test.ts | 74 +++--- evm/evm-codec/test/function.test.ts | 139 +++++------ evm/evm-codec/test/sink.test.ts | 173 ++++++-------- evm/evm-codec/test/src.test.ts | 216 ++++++++--------- evm/evm-codec/test/struct.bench.ts | 179 +++++++-------- evm/evm-codec/test/struct.test.ts | 123 +++++----- evm/evm-codec/tsconfig.json | 4 +- 21 files changed, 995 insertions(+), 1140 deletions(-) create mode 100644 evm/evm-codec/.prettierrc diff --git a/evm/evm-codec/.prettierrc b/evm/evm-codec/.prettierrc new file mode 100644 index 000000000..0a1d0edd1 --- /dev/null +++ b/evm/evm-codec/.prettierrc @@ -0,0 +1,7 @@ +{ + "trailingComma": "all", + "tabWidth": 2, + "semi": false, + "singleQuote": true, + "printWidth": 120 +} diff --git a/evm/evm-codec/package.json b/evm/evm-codec/package.json index 40eb6bd40..0817cd91f 100644 --- a/evm/evm-codec/package.json +++ b/evm/evm-codec/package.json @@ -16,8 +16,7 @@ "build": "rm -rf lib && tsc -p tsconfig.build.json", "test": "vitest run" }, - "dependencies": { - }, + "dependencies": {}, "devDependencies": { "@types/node": "^18.18.14", "ethers": "^5.7.2", diff --git a/evm/evm-codec/src/abi-components/event.ts b/evm/evm-codec/src/abi-components/event.ts index 34bb418d4..fa57e6b00 100644 --- a/evm/evm-codec/src/abi-components/event.ts +++ b/evm/evm-codec/src/abi-components/event.ts @@ -1,27 +1,25 @@ -import { bytes32 } from "../codecs/primitives"; -import { Src } from "../src"; -import { Codec, StructTypes } from "../codec"; -import type { Pretty } from "../utils"; +import { bytes32 } from '../codecs/primitives' +import { Src } from '../src' +import { Codec, StructTypes } from '../codec' +import type { Pretty } from '../utils' export interface EventRecord { - topics: string[]; - data: string; + topics: string[] + data: string } type EventArgs = { - [key: string]: Pretty & { indexed?: boolean }>; -}; + [key: string]: Pretty & { indexed?: boolean }> +} export type IndexedCodecs = Pretty<{ - [K in keyof T]: T[K] extends { indexed: true; isDynamic: true } - ? typeof bytes32 & { indexed: true } - : T[K]; -}>; + [K in keyof T]: T[K] extends { indexed: true; isDynamic: true } ? typeof bytes32 & { indexed: true } : T[K] +}> export class AbiEvent { - public readonly params: any; + public readonly params: any constructor(public readonly topic: string, args: T) { - const entries = Object.entries(args); + const entries = Object.entries(args) this.params = Object.fromEntries( entries.map( ([key, arg]) => @@ -34,28 +32,28 @@ export class AbiEvent { indexed: true, } : arg, - ] as const - ) - ) as IndexedCodecs; + ] as const, + ), + ) as IndexedCodecs } is(rec: EventRecord): boolean { - return rec.topics[0] === this.topic; + return rec.topics[0] === this.topic } decode(rec: EventRecord): StructTypes> { - const src = new Src(Buffer.from(rec.data.slice(2), "hex")); - const result = {} as any; - let topicCounter = 1; + const src = new Src(Buffer.from(rec.data.slice(2), 'hex')) + const result = {} as any + let topicCounter = 1 for (let i in this.params) { if (this.params[i].indexed) { - const topic = rec.topics[topicCounter++]; - const topicSrc = new Src(Buffer.from(topic.slice(2), "hex")); - result[i] = this.params[i].decode(topicSrc); + const topic = rec.topics[topicCounter++] + const topicSrc = new Src(Buffer.from(topic.slice(2), 'hex')) + result[i] = this.params[i].decode(topicSrc) } else { - result[i] = this.params[i].decode(src); + result[i] = this.params[i].decode(src) } } - return result; + return result } } diff --git a/evm/evm-codec/src/abi-components/function.ts b/evm/evm-codec/src/abi-components/function.ts index 9c22d4e7e..18dcb9edd 100644 --- a/evm/evm-codec/src/abi-components/function.ts +++ b/evm/evm-codec/src/abi-components/function.ts @@ -1,78 +1,62 @@ -import { Codec, Struct, StructTypes } from "../codec"; -import { Sink } from "../sink"; -import { slotsCount } from "../utils"; -import { Src } from "../src"; -import assert from "node:assert"; - -type FunctionReturn = T extends Codec - ? U - : T extends Struct - ? StructTypes - : undefined; - -export class AbiFunction< - const T extends Struct, - const R extends Codec | Struct | undefined -> { - readonly #selector: Buffer; - private readonly slotsCount: number; - - constructor( - public selector: string, - public readonly args: T, - public readonly returnType?: R - ) { - assert(selector.startsWith("0x"), "selector must start with 0x"); - assert(selector.length === 10, "selector must be 4 bytes long"); - this.#selector = Buffer.from(selector.slice(2), "hex"); - this.args = args; - this.slotsCount = slotsCount(Object.values(args)); +import { Codec, Struct, StructTypes } from '../codec' +import { Sink } from '../sink' +import { slotsCount } from '../utils' +import { Src } from '../src' +import assert from 'node:assert' + +type FunctionReturn = T extends Codec ? U : T extends Struct ? StructTypes : undefined + +export class AbiFunction | Struct | undefined> { + readonly #selector: Buffer + private readonly slotsCount: number + + constructor(public selector: string, public readonly args: T, public readonly returnType?: R) { + assert(selector.startsWith('0x'), 'selector must start with 0x') + assert(selector.length === 10, 'selector must be 4 bytes long') + this.#selector = Buffer.from(selector.slice(2), 'hex') + this.args = args + this.slotsCount = slotsCount(Object.values(args)) } is(calldata: string) { - return calldata.startsWith(this.selector); + return calldata.startsWith(this.selector) } encode(args: StructTypes) { - const sink = new Sink(this.slotsCount); + const sink = new Sink(this.slotsCount) for (let i in this.args) { - this.args[i].encode(sink, args[i]); + this.args[i].encode(sink, args[i]) } - return `0x${Buffer.concat([this.#selector, sink.result()]).toString( - "hex" - )}`; + return `0x${Buffer.concat([this.#selector, sink.result()]).toString('hex')}` } decode(calldata: string): StructTypes { - assert( - this.is(calldata), - `unexpected function signature: ${calldata.slice(0, 10)}` - ); - const src = new Src(Buffer.from(calldata.slice(10), "hex")); - const result = {} as any; + assert(this.is(calldata), `unexpected function signature: ${calldata.slice(0, 10)}`) + const src = new Src(Buffer.from(calldata.slice(10), 'hex')) + const result = {} as any for (let i in this.args) { - result[i] = this.args[i].decode(src); + result[i] = this.args[i].decode(src) } - return result; + return result } private isCodecs(value: any): value is Codec { - return "decode" in value && "encode" in value; + return 'decode' in value && 'encode' in value } decodeResult(output: string): FunctionReturn { if (!this.returnType) { - return undefined as any; + return undefined as any } - const src = new Src(Buffer.from(output.slice(2), "hex")); + const src = new Src(Buffer.from(output.slice(2), 'hex')) if (this.isCodecs(this.returnType)) { - return this.returnType.decode(src) as any; + return this.returnType.decode(src) as any } - const result = {} as any; + const result = {} as any for (let i in this.returnType) { - const codec = this.returnType[i] as Codec; - result[i] = codec.decode(src); + const codec = this.returnType[i] as Codec + result[i] = codec.decode(src) } - return result; + return result } } diff --git a/evm/evm-codec/src/codec.ts b/evm/evm-codec/src/codec.ts index d98a9605e..9f98d8a52 100644 --- a/evm/evm-codec/src/codec.ts +++ b/evm/evm-codec/src/codec.ts @@ -1,20 +1,20 @@ -import type { Sink } from "./sink"; -import type { Src } from "./src"; -import type { Pretty } from "./utils"; +import type { Sink } from './sink' +import type { Src } from './src' +import type { Pretty } from './utils' -export const WORD_SIZE = 32; +export const WORD_SIZE = 32 export interface Codec { - encode(sink: Sink, val: T): void; - decode(src: Src): T; - isDynamic: boolean; - slotsCount?: number; + encode(sink: Sink, val: T): void + decode(src: Src): T + isDynamic: boolean + slotsCount?: number } export type Struct = { - [key: string]: Codec; -}; + [key: string]: Codec +} export type StructTypes = Pretty<{ - [K in keyof T]: T[K] extends Codec ? U : never; -}>; + [K in keyof T]: T[K] extends Codec ? U : never +}> diff --git a/evm/evm-codec/src/codecs/array.ts b/evm/evm-codec/src/codecs/array.ts index 82c04ab06..b4b624d45 100644 --- a/evm/evm-codec/src/codecs/array.ts +++ b/evm/evm-codec/src/codecs/array.ts @@ -1,85 +1,83 @@ -import { Codec, WORD_SIZE } from "../codec"; -import { Sink } from "../sink"; -import { Src } from "../src"; +import { Codec, WORD_SIZE } from '../codec' +import { Sink } from '../sink' +import { Src } from '../src' export class ArrayCodec implements Codec { - public readonly isDynamic = true; + public readonly isDynamic = true constructor(public readonly item: Codec) {} encode(sink: Sink, val: T[]) { - sink.dynamicOffset(val.length); + sink.dynamicOffset(val.length) for (let i = 0; i < val.length; i++) { - this.item.encode(sink, val[i]); + this.item.encode(sink, val[i]) } - sink.increaseSize(WORD_SIZE); - sink.endDynamic(); + sink.increaseSize(WORD_SIZE) + sink.endDynamic() } decode(src: Src): T[] { - const offset = src.u32(); + const offset = src.u32() - src.safeJump(offset); - const len = src.u32(); + src.safeJump(offset) + const len = src.u32() - const tmpSrc = src.slice(offset + WORD_SIZE); - const val = new Array(len); + const tmpSrc = src.slice(offset + WORD_SIZE) + const val = new Array(len) for (let i = 0; i < val.length; i++) { - val[i] = this.item.decode(tmpSrc); + val[i] = this.item.decode(tmpSrc) } - src.jumpBack(); - return val; + src.jumpBack() + return val } } export class FixedSizeArrayCodec implements Codec { - public isDynamic: boolean; - public slotsCount: number; + public isDynamic: boolean + public slotsCount: number constructor(public readonly item: Codec, public readonly size: number) { - this.isDynamic = item.isDynamic && size > 0; - this.slotsCount = this.isDynamic ? 1 : size; + this.isDynamic = item.isDynamic && size > 0 + this.slotsCount = this.isDynamic ? 1 : size } encode(sink: Sink, val: T[]) { if (val.length !== this.size) { - throw new Error( - `invalid array length: ${val.length}. Expected: ${this.size}` - ); + throw new Error(`invalid array length: ${val.length}. Expected: ${this.size}`) } if (this.isDynamic) { - return this.encodeDynamic(sink, val); + return this.encodeDynamic(sink, val) } for (let i = 0; i < this.size; i++) { - this.item.encode(sink, val[i]); + this.item.encode(sink, val[i]) } } private encodeDynamic(sink: Sink, val: T[]) { - sink.offset(this.size); + sink.offset(this.size) for (let i = 0; i < val.length; i++) { - this.item.encode(sink, val[i]); + this.item.encode(sink, val[i]) } - sink.endDynamic(); + sink.endDynamic() } decode(src: Src): T[] { if (this.isDynamic) { - return this.decodeDynamic(src); + return this.decodeDynamic(src) } - let val = new Array(this.size); + let val = new Array(this.size) for (let i = 0; i < val.length; i++) { - val[i] = this.item.decode(src); + val[i] = this.item.decode(src) } - return val; + return val } private decodeDynamic(src: Src): T[] { - const offset = src.u32(); - const tmpSrc = src.slice(offset); - let val = new Array(this.size); + const offset = src.u32() + const tmpSrc = src.slice(offset) + let val = new Array(this.size) for (let i = 0; i < val.length; i++) { - val[i] = this.item.decode(tmpSrc); + val[i] = this.item.decode(tmpSrc) } - return val; + return val } } diff --git a/evm/evm-codec/src/codecs/primitives.ts b/evm/evm-codec/src/codecs/primitives.ts index ec5a09dc6..3a4c36a15 100644 --- a/evm/evm-codec/src/codecs/primitives.ts +++ b/evm/evm-codec/src/codecs/primitives.ts @@ -1,243 +1,237 @@ -import { Codec } from "../codec"; -import { Sink } from "../sink"; -import { Src } from "../src"; -import { ArrayCodec, FixedSizeArrayCodec } from "./array"; -import { StructCodec } from "./struct"; -import { AbiFunction } from "../abi-components/function"; -import { AbiEvent } from "../abi-components/event"; +import { Codec } from '../codec' +import { Sink } from '../sink' +import { Src } from '../src' +import { ArrayCodec, FixedSizeArrayCodec } from './array' +import { StructCodec } from './struct' +import { AbiFunction } from '../abi-components/function' +import { AbiEvent } from '../abi-components/event' export const bool: Codec = { encode: function (sink: Sink, val: boolean) { - sink.bool(val); + sink.bool(val) }, decode(src: Src): boolean { - return src.bool(); + return src.bool() }, isDynamic: false, -}; +} export const uint8: Codec = { encode(sink: Sink, val: number) { - sink.u8(val); + sink.u8(val) }, decode(src: Src): number { - return src.u8(); + return src.u8() }, isDynamic: false, -}; +} export const int8: Codec = { encode(sink: Sink, val: number) { - sink.i8(val); + sink.i8(val) }, decode(src: Src): number { - return src.i8(); + return src.i8() }, isDynamic: false, -}; +} export const uint16: Codec = { encode(sink: Sink, val: number) { - sink.u16(val); + sink.u16(val) }, decode(src: Src): number { - return src.u16(); + return src.u16() }, isDynamic: false, -}; +} export const int16: Codec = { encode(sink: Sink, val: number) { - sink.i16(val); + sink.i16(val) }, decode(src: Src): number { - return src.i16(); + return src.i16() }, isDynamic: false, -}; +} export const uint32: Codec = { encode(sink: Sink, val: number) { - sink.u32(val); + sink.u32(val) }, decode(src: Src): number { - return src.u32(); + return src.u32() }, isDynamic: false, -}; +} export const int32: Codec = { encode(sink: Sink, val: number) { - sink.i32(val); + sink.i32(val) }, decode(src: Src): number { - return src.i32(); + return src.i32() }, isDynamic: false, -}; +} export const uint64: Codec = { encode(sink: Sink, val: bigint) { - sink.u64(val); + sink.u64(val) }, decode(src: Src): bigint { - return src.u64(); + return src.u64() }, isDynamic: false, -}; +} export const int64: Codec = { encode(sink: Sink, val: bigint) { - sink.i64(val); + sink.i64(val) }, decode(src: Src): bigint { - return src.i64(); + return src.i64() }, isDynamic: false, -}; +} export const uint128: Codec = { encode(sink: Sink, val: bigint) { - sink.u128(val); + sink.u128(val) }, decode(src: Src): bigint { - return src.u128(); + return src.u128() }, isDynamic: false, -}; +} export const int128: Codec = { encode(sink: Sink, val: bigint) { - sink.i128(val); + sink.i128(val) }, decode(src: Src): bigint { - return src.i128(); + return src.i128() }, isDynamic: false, -}; +} export const uint256: Codec = { encode(sink: Sink, val: bigint) { - sink.u256(val); + sink.u256(val) }, decode(src: Src): bigint { - return src.u256(); + return src.u256() }, isDynamic: false, -}; +} export const int256: Codec = { encode(sink: Sink, val: bigint) { - sink.i256(val); + sink.i256(val) }, decode(src: Src): bigint { - return src.i256(); + return src.i256() }, isDynamic: false, -}; +} export const string = { encode(sink: Sink, val: string) { - sink.offset(); - sink.string(val); - sink.endDynamic(); + sink.offset() + sink.string(val) + sink.endDynamic() }, decode(src: Src): string { - return src.string(); + return src.string() }, isDynamic: true, -}; +} export const bytes = { encode(sink: Sink, val: Uint8Array) { - sink.offset(); - sink.bytes(val); - sink.endDynamic(); + sink.offset() + sink.bytes(val) + sink.endDynamic() }, decode(src: Src): Uint8Array { - return src.bytes(); + return src.bytes() }, isDynamic: true, -}; +} const bytesN = (size: number): Codec => ({ encode(sink: Sink, val: Uint8Array) { - sink.staticBytes(size, val); + sink.staticBytes(size, val) }, decode(src: Src): Uint8Array { - return src.staticBytes(size); + return src.staticBytes(size) }, isDynamic: false, -}); - -export const bytes0 = bytesN(0); -export const bytes1 = bytesN(1); -export const bytes2 = bytesN(2); -export const bytes3 = bytesN(3); -export const bytes4 = bytesN(4); -export const bytes5 = bytesN(5); -export const bytes6 = bytesN(6); -export const bytes7 = bytesN(7); -export const bytes8 = bytesN(8); -export const bytes9 = bytesN(9); -export const bytes10 = bytesN(10); -export const bytes11 = bytesN(11); -export const bytes12 = bytesN(12); -export const bytes13 = bytesN(13); -export const bytes14 = bytesN(14); -export const bytes15 = bytesN(15); -export const bytes16 = bytesN(16); -export const bytes17 = bytesN(17); -export const bytes18 = bytesN(18); -export const bytes19 = bytesN(19); -export const bytes20 = bytesN(20); -export const bytes21 = bytesN(21); -export const bytes22 = bytesN(22); -export const bytes23 = bytesN(23); -export const bytes24 = bytesN(24); -export const bytes25 = bytesN(25); -export const bytes26 = bytesN(26); -export const bytes27 = bytesN(27); -export const bytes28 = bytesN(28); -export const bytes29 = bytesN(29); -export const bytes30 = bytesN(30); -export const bytes31 = bytesN(31); -export const bytes32 = bytesN(32); +}) + +export const bytes0 = bytesN(0) +export const bytes1 = bytesN(1) +export const bytes2 = bytesN(2) +export const bytes3 = bytesN(3) +export const bytes4 = bytesN(4) +export const bytes5 = bytesN(5) +export const bytes6 = bytesN(6) +export const bytes7 = bytesN(7) +export const bytes8 = bytesN(8) +export const bytes9 = bytesN(9) +export const bytes10 = bytesN(10) +export const bytes11 = bytesN(11) +export const bytes12 = bytesN(12) +export const bytes13 = bytesN(13) +export const bytes14 = bytesN(14) +export const bytes15 = bytesN(15) +export const bytes16 = bytesN(16) +export const bytes17 = bytesN(17) +export const bytes18 = bytesN(18) +export const bytes19 = bytesN(19) +export const bytes20 = bytesN(20) +export const bytes21 = bytesN(21) +export const bytes22 = bytesN(22) +export const bytes23 = bytesN(23) +export const bytes24 = bytesN(24) +export const bytes25 = bytesN(25) +export const bytes26 = bytesN(26) +export const bytes27 = bytesN(27) +export const bytes28 = bytesN(28) +export const bytes29 = bytesN(29) +export const bytes30 = bytesN(30) +export const bytes31 = bytesN(31) +export const bytes32 = bytesN(32) export const address: Codec = { encode(sink: Sink, val: string) { - sink.address(val); + sink.address(val) }, decode(src: Src): string { - return src.address(); + return src.address() }, isDynamic: false, -}; +} -export const fixedSizeArray = (item: Codec, size: number): Codec => - new FixedSizeArrayCodec(item, size); +export const fixedSizeArray = (item: Codec, size: number): Codec => new FixedSizeArrayCodec(item, size) -export const array = (item: Codec): Codec => new ArrayCodec(item); +export const array = (item: Codec): Codec => new ArrayCodec(item) type Struct = { - [key: string]: Codec; -}; + [key: string]: Codec +} -export const struct = (components: T) => - new StructCodec(components); +export const struct = (components: T) => new StructCodec(components) -export const tuple = struct; +export const tuple = struct -export const fun = < - const T extends Struct, - const R extends Codec | Struct | undefined ->( +export const fun = | Struct | undefined>( signature: string, args: T, - returnType?: R -) => new AbiFunction(signature, args, returnType); + returnType?: R, +) => new AbiFunction(signature, args, returnType) -export const event = (topic: string, args: T) => - new AbiEvent(topic, args); +export const event = (topic: string, args: T) => new AbiEvent(topic, args) -export { indexed } from "../utils"; +export { indexed } from '../utils' diff --git a/evm/evm-codec/src/codecs/struct.ts b/evm/evm-codec/src/codecs/struct.ts index 8263230ec..0bf1145d9 100644 --- a/evm/evm-codec/src/codecs/struct.ts +++ b/evm/evm-codec/src/codecs/struct.ts @@ -1,69 +1,67 @@ -import { Codec, Struct, StructTypes } from "../codec"; -import { Sink } from "../sink"; -import { Src } from "../src"; -import { slotsCount } from "../utils"; +import { Codec, Struct, StructTypes } from '../codec' +import { Sink } from '../sink' +import { Src } from '../src' +import { slotsCount } from '../utils' -export class StructCodec - implements Codec> -{ - public readonly isDynamic: boolean; - public readonly slotsCount: number; - private readonly childrenSlotsCount: number; - private readonly components: T; +export class StructCodec implements Codec> { + public readonly isDynamic: boolean + public readonly slotsCount: number + private readonly childrenSlotsCount: number + private readonly components: T constructor(components: T) { - this.components = components; - const codecs = Object.values(components); - this.isDynamic = codecs.some((codec) => codec.isDynamic); - this.childrenSlotsCount = slotsCount(codecs); + this.components = components + const codecs = Object.values(components) + this.isDynamic = codecs.some((codec) => codec.isDynamic) + this.childrenSlotsCount = slotsCount(codecs) if (this.isDynamic) { - this.slotsCount = 1; + this.slotsCount = 1 } else { - this.slotsCount = this.childrenSlotsCount; + this.slotsCount = this.childrenSlotsCount } } public encode(sink: Sink, val: StructTypes): void { if (this.isDynamic) { - this.encodeDynamic(sink, val); - return; + this.encodeDynamic(sink, val) + return } for (let i in this.components) { - let prop = this.components[i]; - prop.encode(sink, val[i]); + let prop = this.components[i] + prop.encode(sink, val[i]) } } private encodeDynamic(sink: Sink, val: StructTypes): void { - sink.offset(this.childrenSlotsCount); + sink.offset(this.childrenSlotsCount) for (let i in this.components) { - let prop = this.components[i]; - prop.encode(sink, val[i]); + let prop = this.components[i] + prop.encode(sink, val[i]) } - sink.endDynamic(); + sink.endDynamic() } public decode(src: Src): StructTypes { if (this.isDynamic) { - return this.decodeDynamic(src); + return this.decodeDynamic(src) } - let result: any = {}; + let result: any = {} for (let i in this.components) { - let prop = this.components[i]; - result[i] = prop.decode(src); + let prop = this.components[i] + result[i] = prop.decode(src) } - return result; + return result } private decodeDynamic(src: Src): StructTypes { - let result: any = {}; + let result: any = {} - const offset = src.u32(); - const tmpSrc = src.slice(offset); + const offset = src.u32() + const tmpSrc = src.slice(offset) for (let i in this.components) { - let prop = this.components[i]; - result[i] = prop.decode(tmpSrc); + let prop = this.components[i] + result[i] = prop.decode(tmpSrc) } - return result; + return result } } diff --git a/evm/evm-codec/src/contract-base.ts b/evm/evm-codec/src/contract-base.ts index 2b67a6435..24580b205 100644 --- a/evm/evm-codec/src/contract-base.ts +++ b/evm/evm-codec/src/contract-base.ts @@ -1,47 +1,43 @@ -import { AbiFunction } from "./abi-components/function"; -import { Codec, Struct, StructTypes } from "./codec"; +import { AbiFunction } from './abi-components/function' +import { Codec, Struct, StructTypes } from './codec' export interface Chain { client: { - call: (method: string, params?: unknown[]) => Promise; - }; + call: (method: string, params?: unknown[]) => Promise + } } export interface ChainContext { - _chain: Chain; + _chain: Chain } export interface BlockContext { - _chain: Chain; - block: Block; + _chain: Chain + block: Block } export interface Block { - height: number; + height: number } export class ContractBase { - private readonly _chain: Chain; - private readonly blockHeight: number; - readonly address: string; - - constructor(ctx: BlockContext, address: string); - constructor(ctx: ChainContext, block: Block, address: string); - constructor( - ctx: BlockContext, - blockOrAddress: Block | string, - address?: string - ) { - this._chain = ctx._chain; - if (typeof blockOrAddress === "string") { - this.blockHeight = ctx.block.height; - this.address = blockOrAddress; + private readonly _chain: Chain + private readonly blockHeight: number + readonly address: string + + constructor(ctx: BlockContext, address: string) + constructor(ctx: ChainContext, block: Block, address: string) + constructor(ctx: BlockContext, blockOrAddress: Block | string, address?: string) { + this._chain = ctx._chain + if (typeof blockOrAddress === 'string') { + this.blockHeight = ctx.block.height + this.address = blockOrAddress } else { if (address == null) { - throw new Error("missing contract address"); + throw new Error('missing contract address') } - this.blockHeight = blockOrAddress.height; - this.address = address; + this.blockHeight = blockOrAddress.height + this.address = address } } @@ -50,18 +46,18 @@ export class ContractBase { * Might be necessary to override for some chains. */ private async rpc_call(calldata: string) { - return this._chain.client.call("eth_call", [ + return this._chain.client.call('eth_call', [ { to: this.address, data: calldata }, - "0x" + this.blockHeight.toString(16), - ]); + '0x' + this.blockHeight.toString(16), + ]) } - async eth_call< - const T extends Struct, - const R extends Codec | Struct | undefined - >(func: AbiFunction, args: StructTypes): Promise { - const data = func.encode(args); - const result = await this.rpc_call(data); - return func.decodeResult(result); + async eth_call | Struct | undefined>( + func: AbiFunction, + args: StructTypes, + ): Promise { + const data = func.encode(args) + const result = await this.rpc_call(data) + return func.decodeResult(result) } } diff --git a/evm/evm-codec/src/index.ts b/evm/evm-codec/src/index.ts index 608718159..fa6dbd36b 100644 --- a/evm/evm-codec/src/index.ts +++ b/evm/evm-codec/src/index.ts @@ -1,5 +1,5 @@ -export { Src } from "./src"; -export { Sink } from "./sink"; -export type { Codec } from "./codec"; -export * from "./codecs/primitives"; -export * from "./contract-base"; +export { Src } from './src' +export { Sink } from './sink' +export type { Codec } from './codec' +export * from './codecs/primitives' +export * from './contract-base' diff --git a/evm/evm-codec/src/sink.ts b/evm/evm-codec/src/sink.ts index 783f45543..35d041bed 100644 --- a/evm/evm-codec/src/sink.ts +++ b/evm/evm-codec/src/sink.ts @@ -1,219 +1,208 @@ -import assert from "node:assert"; -import { WORD_SIZE } from "./codec"; +import assert from 'node:assert' +import { WORD_SIZE } from './codec' export class Sink { - private pos = 0; - private buf: Buffer; - private view: DataView; - private stack: { start: number; prev: number; size: number }[] = []; + private pos = 0 + private buf: Buffer + private view: DataView + private stack: { start: number; prev: number; size: number }[] = [] constructor(fields: number, capacity: number = 1280) { this.stack.push({ start: 0, prev: 0, size: fields * WORD_SIZE, - }); - this.buf = Buffer.alloc(capacity); - this.view = new DataView( - this.buf.buffer, - this.buf.byteOffset, - this.buf.byteLength - ); + }) + this.buf = Buffer.alloc(capacity) + this.view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength) } result(): Buffer { - assert( - this.stack.length === 1, - "Cannot get result during dynamic encoding" - ); - return this.buf.subarray(0, this.size()); + assert(this.stack.length === 1, 'Cannot get result during dynamic encoding') + return this.buf.subarray(0, this.size()) } toString() { - return "0x" + this.result().toString("hex"); + return '0x' + this.result().toString('hex') } reserve(additional: number): void { if (this.buf.length - this.pos < additional) { - this._allocate(this.pos + additional); + this._allocate(this.pos + additional) } } size() { - return this.stack[this.stack.length - 1].size; + return this.stack[this.stack.length - 1].size } private _allocate(cap: number): void { - cap = Math.max(cap, this.buf.length * 2); - let buf = Buffer.alloc(cap); - buf.set(this.buf); - this.buf = buf; - this.view = new DataView( - this.buf.buffer, - this.buf.byteOffset, - this.buf.byteLength - ); + cap = Math.max(cap, this.buf.length * 2) + let buf = Buffer.alloc(cap) + buf.set(this.buf) + this.buf = buf + this.view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength) } u8(val: number) { - this.reserve(WORD_SIZE); - this.pos += WORD_SIZE - 1; - this.view.setUint8(this.pos, val); - this.pos += 1; + this.reserve(WORD_SIZE) + this.pos += WORD_SIZE - 1 + this.view.setUint8(this.pos, val) + this.pos += 1 } i8(val: number) { - this.i256(BigInt(val)); + this.i256(BigInt(val)) } u16(val: number) { - this.reserve(WORD_SIZE); - this.pos += WORD_SIZE - 2; - this.view.setUint16(this.pos, val, false); - this.pos += 2; + this.reserve(WORD_SIZE) + this.pos += WORD_SIZE - 2 + this.view.setUint16(this.pos, val, false) + this.pos += 2 } i16(val: number) { - this.i256(BigInt(val)); + this.i256(BigInt(val)) } u32(val: number) { - this.reserve(WORD_SIZE); - this.pos += WORD_SIZE - 4; - this.view.setUint32(this.pos, val, false); - this.pos += 4; + this.reserve(WORD_SIZE) + this.pos += WORD_SIZE - 4 + this.view.setUint32(this.pos, val, false) + this.pos += 4 } i32(val: number) { - this.i256(BigInt(val)); + this.i256(BigInt(val)) } u64(val: bigint) { - this.reserve(WORD_SIZE); - this.pos += WORD_SIZE - 8; - this.view.setBigUint64(this.pos, val, false); - this.pos += 8; + this.reserve(WORD_SIZE) + this.pos += WORD_SIZE - 8 + this.view.setBigUint64(this.pos, val, false) + this.pos += 8 } i64(val: bigint) { - this.i256(val); + this.i256(val) } #u64(val: bigint) { - this.view.setBigUint64(this.pos, val, false); - this.pos += 8; + this.view.setBigUint64(this.pos, val, false) + this.pos += 8 } u128(val: bigint) { - this.reserve(WORD_SIZE); - this.pos += WORD_SIZE - 16; - this.#u64(val & 0xffffffffffffffffn); - this.#u64(val >> 64n); + this.reserve(WORD_SIZE) + this.pos += WORD_SIZE - 16 + this.#u64(val & 0xffffffffffffffffn) + this.#u64(val >> 64n) } i128(val: bigint) { - this.i256(BigInt(val)); + this.i256(BigInt(val)) } #u128(val: bigint) { - this.reserve(WORD_SIZE); - this.#u64(val >> 64n); - this.#u64(val & 0xffffffffffffffffn); + this.reserve(WORD_SIZE) + this.#u64(val >> 64n) + this.#u64(val & 0xffffffffffffffffn) } u256(val: bigint) { - this.reserve(WORD_SIZE); - this.#u128(val >> 128n); - this.#u128(val & (2n ** 128n - 1n)); + this.reserve(WORD_SIZE) + this.#u128(val >> 128n) + this.#u128(val & (2n ** 128n - 1n)) } i256(val: bigint) { - let base = 2n ** 256n; - val = (val + base) % base; - this.u256(val); + let base = 2n ** 256n + val = (val + base) % base + this.u256(val) } bytes(val: Uint8Array) { - const size = Buffer.byteLength(val); - this.u32(size); - const wordsCount = Math.ceil(size / WORD_SIZE); - const reservedSize = WORD_SIZE * wordsCount; - this.reserve(reservedSize); - this.buf.set(val, this.pos); - this.pos += reservedSize; - this.increaseSize(reservedSize + WORD_SIZE); + const size = Buffer.byteLength(val) + this.u32(size) + const wordsCount = Math.ceil(size / WORD_SIZE) + const reservedSize = WORD_SIZE * wordsCount + this.reserve(reservedSize) + this.buf.set(val, this.pos) + this.pos += reservedSize + this.increaseSize(reservedSize + WORD_SIZE) } staticBytes(len: number, val: Uint8Array) { if (len > 32) { - throw new Error(`bytes${len} is not a valid type`); + throw new Error(`bytes${len} is not a valid type`) } - const size = Buffer.byteLength(val); + const size = Buffer.byteLength(val) if (size > len) { - throw new Error(`invalid data size for bytes${len}`); + throw new Error(`invalid data size for bytes${len}`) } - this.reserve(WORD_SIZE); - this.buf.set(val, this.pos); - this.pos += WORD_SIZE; + this.reserve(WORD_SIZE) + this.buf.set(val, this.pos) + this.pos += WORD_SIZE } address(val: string) { - this.u256(BigInt(val)); + this.u256(BigInt(val)) } string(val: string) { - const size = Buffer.byteLength(val); - this.u32(size); - const wordsCount = Math.ceil(size / WORD_SIZE); - const reservedSize = WORD_SIZE * wordsCount; - this.reserve(reservedSize); - this.buf.write(val, this.pos); - this.pos += reservedSize; - this.increaseSize(reservedSize + WORD_SIZE); + const size = Buffer.byteLength(val) + this.u32(size) + const wordsCount = Math.ceil(size / WORD_SIZE) + const reservedSize = WORD_SIZE * wordsCount + this.reserve(reservedSize) + this.buf.write(val, this.pos) + this.pos += reservedSize + this.increaseSize(reservedSize + WORD_SIZE) } bool(val: boolean) { - this.u8(val ? 1 : 0); + this.u8(val ? 1 : 0) } offset(slotsCount = 0) { - const ptr = this.size(); - this.u32(ptr); - const _start = this.start(); - this.startDynamic(_start + ptr, slotsCount); - this.pos = _start + ptr; + const ptr = this.size() + this.u32(ptr) + const _start = this.start() + this.startDynamic(_start + ptr, slotsCount) + this.pos = _start + ptr } dynamicOffset(slotsCount: number) { - const ptr = this.size(); - this.u32(ptr); - const _start = this.start(); - this.startDynamic(_start + ptr + WORD_SIZE, slotsCount); - this.pos = _start + ptr; - this.u32(slotsCount); + const ptr = this.size() + this.u32(ptr) + const _start = this.start() + this.startDynamic(_start + ptr + WORD_SIZE, slotsCount) + this.pos = _start + ptr + this.u32(slotsCount) } private start() { - return this.stack[this.stack.length - 1].start; + return this.stack[this.stack.length - 1].start } public increaseSize(amount: number) { - this.stack[this.stack.length - 1].size += amount; + this.stack[this.stack.length - 1].size += amount } private startDynamic(start: number, slotsCount: number) { - const size = slotsCount * WORD_SIZE; - this.reserve(start + size); + const size = slotsCount * WORD_SIZE + this.reserve(start + size) this.stack.push({ start, prev: this.pos, size, - }); + }) } endDynamic() { - assert(this.stack.length > 1, "No dynamic encoding started"); - const { prev, size } = this.stack.pop()!; - this.increaseSize(size); - this.pos = prev; + assert(this.stack.length > 1, 'No dynamic encoding started') + const { prev, size } = this.stack.pop()! + this.increaseSize(size) + this.pos = prev } } diff --git a/evm/evm-codec/src/src.ts b/evm/evm-codec/src/src.ts index ecd47a5eb..de66ecb29 100644 --- a/evm/evm-codec/src/src.ts +++ b/evm/evm-codec/src/src.ts @@ -1,164 +1,158 @@ -import { WORD_SIZE } from "./codec"; +import { WORD_SIZE } from './codec' export class Src { - private view: DataView; - private pos = 0; - private oldPos = 0; + private view: DataView + private pos = 0 + private oldPos = 0 constructor(private buf: Uint8Array) { - this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); + this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength) } slice(start: number, end?: number): Src { - return new Src(this.buf.subarray(start, end)); + return new Src(this.buf.subarray(start, end)) } u8(): number { - this.pos += WORD_SIZE - 1; - let val = this.view.getUint8(this.pos); - this.pos += 1; - return val; + this.pos += WORD_SIZE - 1 + let val = this.view.getUint8(this.pos) + this.pos += 1 + return val } i8(): number { - return Number(this.i256()); + return Number(this.i256()) } u16(): number { - this.pos += WORD_SIZE - 2; - let val = this.view.getUint16(this.pos, false); - this.pos += 2; - return val; + this.pos += WORD_SIZE - 2 + let val = this.view.getUint16(this.pos, false) + this.pos += 2 + return val } i16(): number { - return Number(this.i256()); + return Number(this.i256()) } u32(): number { - this.pos += WORD_SIZE - 4; - let val = this.view.getUint32(this.pos, false); - this.pos += 4; - return val; + this.pos += WORD_SIZE - 4 + let val = this.view.getUint32(this.pos, false) + this.pos += 4 + return val } i32(): number { - return Number(this.i256()); + return Number(this.i256()) } u64(): bigint { - this.pos += WORD_SIZE - 8; - return this.#u64(); + this.pos += WORD_SIZE - 8 + return this.#u64() } #u64(): bigint { - let val = this.view.getBigUint64(this.pos, false); - this.pos += 8; - return val; + let val = this.view.getBigUint64(this.pos, false) + this.pos += 8 + return val } i64(): bigint { - this.pos += WORD_SIZE - 8; - return this.#i64(); + this.pos += WORD_SIZE - 8 + return this.#i64() } #i64(): bigint { - let val = this.view.getBigInt64(this.pos, false); - this.pos += 8; - return val; + let val = this.view.getBigInt64(this.pos, false) + this.pos += 8 + return val } u128(): bigint { - this.pos += WORD_SIZE - 16; - return this.#u128(); + this.pos += WORD_SIZE - 16 + return this.#u128() } #u128(): bigint { - let hi = this.#u64(); - let lo = this.#u64(); - return lo + (hi << 64n); + let hi = this.#u64() + let lo = this.#u64() + return lo + (hi << 64n) } i128(): bigint { - this.pos += WORD_SIZE - 16; - return this.#i128(); + this.pos += WORD_SIZE - 16 + return this.#i128() } #i128(): bigint { - let hi = this.#i64(); - let lo = this.#u64(); - return lo + (hi << 64n); + let hi = this.#i64() + let lo = this.#u64() + return lo + (hi << 64n) } u256(): bigint { - let hi = this.#u128(); - let lo = this.#u128(); - return lo + (hi << 128n); + let hi = this.#u128() + let lo = this.#u128() + return lo + (hi << 128n) } i256(): bigint { - let hi = this.#i128(); - let lo = this.#u128(); - return lo + (hi << 128n); + let hi = this.#i128() + let lo = this.#u128() + return lo + (hi << 128n) } address(): string { - return "0x" + this.u256().toString(16).padStart(40, "0"); + return '0x' + this.u256().toString(16).padStart(40, '0') } bytes(): Uint8Array { - const ptr = this.u32(); - this.safeJump(ptr); - const len = this.u32(); - this.assertLength(len); - const val = this.buf.subarray(this.pos, this.pos + len); - this.jumpBack(); - return val; + const ptr = this.u32() + this.safeJump(ptr) + const len = this.u32() + this.assertLength(len) + const val = this.buf.subarray(this.pos, this.pos + len) + this.jumpBack() + return val } staticBytes(len: number): Uint8Array { if (len > 32) { - throw new Error(`bytes${len} is not a valid type`); + throw new Error(`bytes${len} is not a valid type`) } - const val = this.buf.subarray(this.pos, this.pos + len); - this.pos += WORD_SIZE; - return val; + const val = this.buf.subarray(this.pos, this.pos + len) + this.pos += WORD_SIZE + return val } string(): string { - const ptr = this.u32(); - this.safeJump(ptr); - const len = this.u32(); - this.assertLength(len); - const val = Buffer.from( - this.buf.buffer, - this.buf.byteOffset + this.pos, - len - ).toString("utf-8"); - this.jumpBack(); - return val; + const ptr = this.u32() + this.safeJump(ptr) + const len = this.u32() + this.assertLength(len) + const val = Buffer.from(this.buf.buffer, this.buf.byteOffset + this.pos, len).toString('utf-8') + this.jumpBack() + return val } bool(): boolean { - return !!this.u8(); + return !!this.u8() } private assertLength(len: number): void { if (this.buf.length - this.pos < len) { - throw new RangeError("Unexpected end of input"); + throw new RangeError('Unexpected end of input') } } public safeJump(pos: number): void { if (pos < 0 || pos >= this.buf.length) { - throw new RangeError( - `Unexpected pointer location: 0x${pos.toString(16)}` - ); + throw new RangeError(`Unexpected pointer location: 0x${pos.toString(16)}`) } - this.oldPos = this.pos; - this.pos = pos; + this.oldPos = this.pos + this.pos = pos } public jumpBack(): void { - this.pos = this.oldPos; + this.pos = this.oldPos } } diff --git a/evm/evm-codec/src/utils.ts b/evm/evm-codec/src/utils.ts index 2a23dbb12..5925e825e 100644 --- a/evm/evm-codec/src/utils.ts +++ b/evm/evm-codec/src/utils.ts @@ -1,36 +1,34 @@ -import type { Codec } from "./codec"; +import type { Codec } from './codec' /** * Combines members of an intersection into a readable type. * * @link https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg */ -export type Pretty = { [K in keyof T]: T[K] } & unknown; +export type Pretty = { [K in keyof T]: T[K] } & unknown export function slotsCount(codecs: readonly Codec[]) { - let count = 0; + let count = 0 for (const codec of codecs) { - count += codec.slotsCount ?? 1; + count += codec.slotsCount ?? 1 } - return count; + return count } -export function indexed>( - codec: T -): Pretty { +export function indexed>(codec: T): Pretty { return new Proxy(codec, { get(target: any, prop, receiver) { - if (prop === "indexed") { - return true; + if (prop === 'indexed') { + return true } - const value = target[prop]; + const value = target[prop] if (value instanceof Function) { return function (...args: any[]) { // @ts-ignore - return value.apply(this === receiver ? target : this, args); - }; + return value.apply(this === receiver ? target : this, args) + } } - return value; + return value }, - }); + }) } diff --git a/evm/evm-codec/test/array.test.ts b/evm/evm-codec/test/array.test.ts index 3f82eb3b4..05f38c8c4 100644 --- a/evm/evm-codec/test/array.test.ts +++ b/evm/evm-codec/test/array.test.ts @@ -1,157 +1,141 @@ -import { describe, expect, it } from "vitest"; -import { - address, - array, - bytes, - fixedSizeArray, - int8, - Sink, - Src, - string, - uint256, -} from "../src"; -import { AbiParameter, encodeAbiParameters } from "viem"; +import { describe, expect, it } from 'vitest' +import { address, array, bytes, fixedSizeArray, int8, Sink, Src, string, uint256 } from '../src' +import { AbiParameter, encodeAbiParameters } from 'viem' function compareTypes(sink: Sink, types: AbiParameter[], values: any[]) { - expect(sink.toString()).toEqual(encodeAbiParameters(types, values)); + expect(sink.toString()).toEqual(encodeAbiParameters(types, values)) } -describe("fixed size array", () => { - it("static types encoding", () => { - const arr = fixedSizeArray(int8, 5); - const sink = new Sink(5); - arr.encode(sink, [1, 2, -3, 4, 5]); - compareTypes(sink, [{ type: "int8[5]" }], [[1, 2, -3, 4, 5]]); - }); +describe('fixed size array', () => { + it('static types encoding', () => { + const arr = fixedSizeArray(int8, 5) + const sink = new Sink(5) + arr.encode(sink, [1, 2, -3, 4, 5]) + compareTypes(sink, [{ type: 'int8[5]' }], [[1, 2, -3, 4, 5]]) + }) - it("static types decoding", () => { - const arr = fixedSizeArray(int8, 5); - const sink = new Sink(5); - arr.encode(sink, [1, 2, -3, -4, 5]); - expect(arr.decode(new Src(sink.result()))).toStrictEqual([1, 2, -3, -4, 5]); - }); + it('static types decoding', () => { + const arr = fixedSizeArray(int8, 5) + const sink = new Sink(5) + arr.encode(sink, [1, 2, -3, -4, 5]) + expect(arr.decode(new Src(sink.result()))).toStrictEqual([1, 2, -3, -4, 5]) + }) - it("dynamic types encoding", () => { - const arr = fixedSizeArray(string, 3); - const sink = new Sink(1); + it('dynamic types encoding', () => { + const arr = fixedSizeArray(string, 3) + const sink = new Sink(1) const data = [ - "aaa", - "a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!", - "dasdas", - ]; - arr.encode(sink, data); - compareTypes(sink, [{ type: "string[3]" }], [data]); - expect(arr.decode(new Src(sink.result()))).toStrictEqual(data); - }); + 'aaa', + 'a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!', + 'dasdas', + ] + arr.encode(sink, data) + compareTypes(sink, [{ type: 'string[3]' }], [data]) + expect(arr.decode(new Src(sink.result()))).toStrictEqual(data) + }) - it("deep nested arrays", () => { - const arr = fixedSizeArray(fixedSizeArray(string, 3), 2); - const sink = new Sink(1); + it('deep nested arrays', () => { + const arr = fixedSizeArray(fixedSizeArray(string, 3), 2) + const sink = new Sink(1) const data = [ - "aaa", - "a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!", - "dasdas", - ]; - arr.encode(sink, [data, data.reverse()]); - compareTypes( - sink, - [{ type: "string[3][2]" }], - [[data.reverse(), data.reverse()]] - ); - }); -}); + 'aaa', + 'a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!', + 'dasdas', + ] + arr.encode(sink, [data, data.reverse()]) + compareTypes(sink, [{ type: 'string[3][2]' }], [[data.reverse(), data.reverse()]]) + }) +}) -describe("dynamic size array", () => { - it("static types encoding", () => { - const arr = array(int8); - const sink = new Sink(1); - arr.encode(sink, [1, 2, -3, 4, 5]); - compareTypes(sink, [{ type: "int8[]" }], [[1, 2, -3, 4, 5]]); - }); +describe('dynamic size array', () => { + it('static types encoding', () => { + const arr = array(int8) + const sink = new Sink(1) + arr.encode(sink, [1, 2, -3, 4, 5]) + compareTypes(sink, [{ type: 'int8[]' }], [[1, 2, -3, 4, 5]]) + }) - it("static types decoding", () => { - const arr = array(int8); - const sink = new Sink(1); - arr.encode(sink, [1, 2, -3, -4, 5]); - expect(arr.decode(new Src(sink.result()))).toStrictEqual([1, 2, -3, -4, 5]); - }); + it('static types decoding', () => { + const arr = array(int8) + const sink = new Sink(1) + arr.encode(sink, [1, 2, -3, -4, 5]) + expect(arr.decode(new Src(sink.result()))).toStrictEqual([1, 2, -3, -4, 5]) + }) - it("array of arrays", () => { - const arr = array(array(int8)); - const sink = new Sink(1); + it('array of arrays', () => { + const arr = array(array(int8)) + const sink = new Sink(1) const data = [ [1, 2, -3, -4, 5], [1, 2, -3, -4, 5], - ]; - arr.encode(sink, data); - compareTypes(sink, [{ type: "int8[][]" }], [data]); - expect(arr.decode(new Src(sink.result()))).toStrictEqual(data); - }); + ] + arr.encode(sink, data) + compareTypes(sink, [{ type: 'int8[][]' }], [data]) + expect(arr.decode(new Src(sink.result()))).toStrictEqual(data) + }) - it("dynamic types encoding", () => { - const arr = array(string); - const sink = new Sink(1); + it('dynamic types encoding', () => { + const arr = array(string) + const sink = new Sink(1) const data = [ - "aaa", - "a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!", - "dasdas", - ]; - arr.encode(sink, data); - compareTypes(sink, [{ type: "string[]" }], [data]); - expect(arr.decode(new Src(sink.result()))).toStrictEqual(data); - }); + 'aaa', + 'a relatively long string to test what happens when the string is long, longer than 32 bytes or even better, longer than 64 bytes!!!', + 'dasdas', + ] + arr.encode(sink, data) + compareTypes(sink, [{ type: 'string[]' }], [data]) + expect(arr.decode(new Src(sink.result()))).toStrictEqual(data) + }) - it("hardcore dynamic types", () => { - const sink = new Sink(5); - const arr1 = array(array(fixedSizeArray(string, 3))); - const arr2 = array(array(uint256)); - const arr3 = array(fixedSizeArray(bytes, 2)); + it('hardcore dynamic types', () => { + const sink = new Sink(5) + const arr1 = array(array(fixedSizeArray(string, 3))) + const arr2 = array(array(uint256)) + const arr3 = array(fixedSizeArray(bytes, 2)) const data1 = [ [ - ["aaa", "bbb", "ccc"], - ["ddd", "eee", "fff"], + ['aaa', 'bbb', 'ccc'], + ['ddd', 'eee', 'fff'], ], - [["ggg", "hhh", "iii"]], - ]; - const data2 = [[1n, 2n, 3n], [], [4n]]; + [['ggg', 'hhh', 'iii']], + ] + const data2 = [[1n, 2n, 3n], [], [4n]] const data3 = [ - [Buffer.from("1234", "hex"), Buffer.from("5678", "hex")], - [Buffer.from("dead", "hex"), Buffer.from("beef", "hex")], - ]; - arr1.encode(sink, data1); - address.encode(sink, "0x1234567890123456789012345678901234567890"); - arr3.encode(sink, data3); - arr2.encode(sink, data2); - uint256.encode(sink, 123n); + [Buffer.from('1234', 'hex'), Buffer.from('5678', 'hex')], + [Buffer.from('dead', 'hex'), Buffer.from('beef', 'hex')], + ] + arr1.encode(sink, data1) + address.encode(sink, '0x1234567890123456789012345678901234567890') + arr3.encode(sink, data3) + arr2.encode(sink, data2) + uint256.encode(sink, 123n) compareTypes( sink, [ - { type: "string[3][][]" }, - { type: "address" }, - { type: "bytes[2][]" }, - { type: "uint256[][]" }, - { type: "uint256" }, + { type: 'string[3][][]' }, + { type: 'address' }, + { type: 'bytes[2][]' }, + { type: 'uint256[][]' }, + { type: 'uint256' }, ], [ data1, - "0x1234567890123456789012345678901234567890", + '0x1234567890123456789012345678901234567890', [ - ["0x1234", "0x5678"], - ["0xdead", "0xbeef"], + ['0x1234', '0x5678'], + ['0xdead', '0xbeef'], ], data2, 123n, - ] - ); + ], + ) - const src = new Src(sink.result()); + const src = new Src(sink.result()) - expect(arr1.decode(src)).toStrictEqual(data1); - expect(address.decode(src)).toBe( - "0x1234567890123456789012345678901234567890" - ); - expect(arr3.decode(src)).toStrictEqual(data3); - expect(arr2.decode(src)).toStrictEqual(data2); - expect(uint256.decode(src)).toBe(123n); - }); -}); + expect(arr1.decode(src)).toStrictEqual(data1) + expect(address.decode(src)).toBe('0x1234567890123456789012345678901234567890') + expect(arr3.decode(src)).toStrictEqual(data3) + expect(arr2.decode(src)).toStrictEqual(data2) + expect(uint256.decode(src)).toBe(123n) + }) +}) diff --git a/evm/evm-codec/test/event.test.ts b/evm/evm-codec/test/event.test.ts index f466dd635..94c4e62a4 100644 --- a/evm/evm-codec/test/event.test.ts +++ b/evm/evm-codec/test/event.test.ts @@ -1,70 +1,58 @@ -import { describe, expect, it } from "vitest"; -import { encodeAbiParameters, encodeEventTopics, parseAbiItem } from "viem"; -import { - bool, - bytes, - indexed, - string, - struct, - uint256, - event as _event, -} from "../src"; +import { describe, expect, it } from 'vitest' +import { encodeAbiParameters, encodeEventTopics, parseAbiItem } from 'viem' +import { bool, bytes, indexed, string, struct, uint256, event as _event } from '../src' -describe("Event", () => { - it("decodes simple args", () => { +describe('Event', () => { + it('decodes simple args', () => { const topics = encodeEventTopics({ - abi: [parseAbiItem("event Test(uint256 indexed a, uint256 b)")], - eventName: "Test", + abi: [parseAbiItem('event Test(uint256 indexed a, uint256 b)')], + eventName: 'Test', args: { a: 123n }, - }); + }) const event = _event(topics[0], { a: indexed(uint256), b: uint256, - }); + }) const decoded = event.decode({ topics, - data: encodeAbiParameters([{ type: "uint256" }], [100n]), - }); - expect(decoded).toEqual({ a: 123n, b: 100n }); - }); + data: encodeAbiParameters([{ type: 'uint256' }], [100n]), + }) + expect(decoded).toEqual({ a: 123n, b: 100n }) + }) - it("decodes complex args", () => { + it('decodes complex args', () => { const topics = encodeEventTopics({ - abi: [ - parseAbiItem( - "event Test(string indexed a, string b, bytes c, (uint256, string) d, bool indexed e)" - ), - ], - eventName: "Test", - args: { a: "xdxdxd", e: true }, - }); + abi: [parseAbiItem('event Test(string indexed a, string b, bytes c, (uint256, string) d, bool indexed e)')], + eventName: 'Test', + args: { a: 'xdxdxd', e: true }, + }) const event = _event(topics[0], { a: indexed(string), b: string, c: bytes, d: struct({ _0: uint256, _1: string }), e: indexed(bool), - }); + }) const decoded = event.decode({ topics, data: encodeAbiParameters( [ - { type: "string" }, - { type: "bytes" }, + { type: 'string' }, + { type: 'bytes' }, { - type: "tuple", - components: [{ type: "uint256" }, { type: "string" }], + type: 'tuple', + components: [{ type: 'uint256' }, { type: 'string' }], }, ], - ["hello", "0x1234", [100n, "world"]] + ['hello', '0x1234', [100n, 'world']], ), - }); + }) expect(decoded).toEqual({ - a: Buffer.from(topics[1].slice(2), "hex"), - b: "hello", + a: Buffer.from(topics[1].slice(2), 'hex'), + b: 'hello', c: Buffer.from([0x12, 0x34]), - d: { _0: 100n, _1: "world" }, + d: { _0: 100n, _1: 'world' }, e: true, - }); - }); -}); + }) + }) +}) diff --git a/evm/evm-codec/test/function.test.ts b/evm/evm-codec/test/function.test.ts index d712ccbc5..d2daef687 100644 --- a/evm/evm-codec/test/function.test.ts +++ b/evm/evm-codec/test/function.test.ts @@ -1,48 +1,37 @@ -import { describe, expect, it } from "vitest"; -import { encodeFunctionData, encodeFunctionResult, parseAbiItem } from "viem"; -import { - array, - bool, - bytes4, - fixedSizeArray, - fun, - int32, - Sink, - string, - struct, - uint256, -} from "../src"; +import { describe, expect, it } from 'vitest' +import { encodeFunctionData, encodeFunctionResult, parseAbiItem } from 'viem' +import { array, bool, bytes4, fixedSizeArray, fun, int32, Sink, string, struct, uint256 } from '../src' -describe("Function", () => { - it("encodes/decodes simple args", () => { - const simpleFunction = fun("0x12345678", { +describe('Function', () => { + it('encodes/decodes simple args', () => { + const simpleFunction = fun('0x12345678', { foo: uint256, _1: int32, _2: bool, - }); + }) const calldata = simpleFunction.encode({ foo: 100n, _1: -420, _2: true, - }); + }) expect(calldata).toBe( - "0x123456780000000000000000000000000000000000000000000000000000000000000064fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5c0000000000000000000000000000000000000000000000000000000000000001" - ); + '0x123456780000000000000000000000000000000000000000000000000000000000000064fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5c0000000000000000000000000000000000000000000000000000000000000001', + ) - const decoded = simpleFunction.decode(calldata); + const decoded = simpleFunction.decode(calldata) expect(decoded).toStrictEqual({ foo: 100n, _1: -420, _2: true, - }); - }); + }) + }) - it("encodes/decodes dynamic args", () => { + it('encodes/decodes dynamic args', () => { const staticStruct = struct({ foo: uint256, bar: bytes4, - }); - const dynamicFunction = fun("0x423917ce", { + }) + const dynamicFunction = fun('0x423917ce', { arg1: array(uint256), arg2: fixedSizeArray(array(uint256), 10), arg3: struct({ @@ -51,7 +40,7 @@ describe("Function", () => { str: staticStruct, }), arg4: staticStruct, - }); + }) const args = { arg1: [100n, 2n], arg2: [[], [1n], [], [], [100n, 2n, 3n], [], [], [1337n], [], []], @@ -67,7 +56,7 @@ describe("Function", () => { foo: 100n, bar: Buffer.from([0x12, 0x34, 0x56, 0x78]), }, - }; + } const viemArgs = [ [100n, 2n], [[], [1n], [], [], [100n, 2n, 3n], [], [], [1337n], [], []], @@ -76,85 +65,81 @@ describe("Function", () => { bar: [1n, 2n, 3n], str: { foo: 123n, - bar: "0x12345678", + bar: '0x12345678', }, }, { foo: 100n, - bar: "0x12345678", + bar: '0x12345678', }, - ] as const; + ] as const - const calldata = dynamicFunction.encode(args); + const calldata = dynamicFunction.encode(args) const expected = encodeFunctionData({ abi: [ { - name: "foo", - type: "function", + name: 'foo', + type: 'function', inputs: [ - { name: "arg1", type: "uint256[]" }, - { name: "arg2", type: "uint256[][10]" }, + { name: 'arg1', type: 'uint256[]' }, + { name: 'arg2', type: 'uint256[][10]' }, { - name: "arg3", - type: "tuple", + name: 'arg3', + type: 'tuple', components: [ - { name: "foo", type: "uint256" }, - { name: "bar", type: "uint256[]" }, + { name: 'foo', type: 'uint256' }, + { name: 'bar', type: 'uint256[]' }, { - name: "str", - type: "tuple", + name: 'str', + type: 'tuple', components: [ - { name: "foo", type: "uint256" }, - { name: "bar", type: "bytes4" }, + { name: 'foo', type: 'uint256' }, + { name: 'bar', type: 'bytes4' }, ], }, ], }, { - name: "arg4", - type: "tuple", + name: 'arg4', + type: 'tuple', components: [ - { name: "foo", type: "uint256" }, - { name: "bar", type: "bytes4" }, + { name: 'foo', type: 'uint256' }, + { name: 'bar', type: 'bytes4' }, ], }, ], }, ], - functionName: "foo", + functionName: 'foo', args: viemArgs, - }); - expect(calldata).toBe(expected); + }) + expect(calldata).toBe(expected) - expect(dynamicFunction.decode(calldata)).toStrictEqual(args); - }); + expect(dynamicFunction.decode(calldata)).toStrictEqual(args) + }) - it("return simple type", () => { + it('return simple type', () => { const simpleFunction = fun( - "0x12345678", + '0x12345678', { foo: uint256, }, - int32 - ); - const sink = new Sink(1); - int32.encode(sink, -420); - sink.toString(); - const output = simpleFunction.decodeResult(sink.toString()); - expect(output).toBe(-420); - }); + int32, + ) + const sink = new Sink(1) + int32.encode(sink, -420) + sink.toString() + const output = simpleFunction.decodeResult(sink.toString()) + expect(output).toBe(-420) + }) - it("return tuple", () => { + it('return tuple', () => { const data = encodeFunctionResult({ - abi: [ - parseAbiItem( - "function foo() external returns (uint256, string memory b)" - ), - ], - functionName: "foo", - result: [100n, "hello"], - }); - const _fun = fun("0x12345678", {}, { _0: uint256, b: string }); - expect(_fun.decodeResult(data)).toStrictEqual({ _0: 100n, b: "hello" }); - }); -}); + abi: [parseAbiItem('function foo() external returns (uint256, string memory b)')], + functionName: 'foo', + result: [100n, 'hello'], + }) + const _fun = fun('0x12345678', {}, { _0: uint256, b: string }) + expect(_fun.decodeResult(data)).toStrictEqual({ _0: 100n, b: 'hello' }) + }) +}) diff --git a/evm/evm-codec/test/sink.test.ts b/evm/evm-codec/test/sink.test.ts index 55e1abdbf..b51e47d1c 100644 --- a/evm/evm-codec/test/sink.test.ts +++ b/evm/evm-codec/test/sink.test.ts @@ -1,116 +1,89 @@ -import { describe, expect, it } from "vitest"; -import { AbiParameter, encodeAbiParameters } from "viem"; -import { Sink } from "../src"; +import { describe, expect, it } from 'vitest' +import { AbiParameter, encodeAbiParameters } from 'viem' +import { Sink } from '../src' -describe("sink", () => { +describe('sink', () => { function compareTypes(sink: Sink, types: AbiParameter[], values: any[]) { - expect(sink.toString()).toEqual(encodeAbiParameters(types, values)); + expect(sink.toString()).toEqual(encodeAbiParameters(types, values)) } - it("negative numbers", () => { - const sink = new Sink(6); - sink.i8(-1); - sink.i16(-123); - sink.i32(-123456); - sink.i64(-1234567890n); - sink.i128(-12345678901234567890n); - sink.i256(-1234567890123456789012345678901234567890n); + it('negative numbers', () => { + const sink = new Sink(6) + sink.i8(-1) + sink.i16(-123) + sink.i32(-123456) + sink.i64(-1234567890n) + sink.i128(-12345678901234567890n) + sink.i256(-1234567890123456789012345678901234567890n) compareTypes( sink, [ - { type: "int8" }, - { type: "int16" }, - { type: "int32" }, - { type: "int64" }, - { type: "int128" }, - { type: "int256" }, + { type: 'int8' }, + { type: 'int16' }, + { type: 'int32' }, + { type: 'int64' }, + { type: 'int128' }, + { type: 'int256' }, ], - [ - -1, - -123, - -123456, - -1234567890n, - -12345678901234567890n, - -1234567890123456789012345678901234567890n, - ] - ); - }); + [-1, -123, -123456, -1234567890n, -12345678901234567890n, -1234567890123456789012345678901234567890n], + ) + }) - it("mixed types", () => { - const sink = new Sink(5); - sink.u8(1); - sink.i8(-2); - sink.address("0x1234567890123456789012345678901234567890"); - sink.u256(3n); - sink.staticBytes(7, Buffer.from("1234567890abcd", "hex")); + it('mixed types', () => { + const sink = new Sink(5) + sink.u8(1) + sink.i8(-2) + sink.address('0x1234567890123456789012345678901234567890') + sink.u256(3n) + sink.staticBytes(7, Buffer.from('1234567890abcd', 'hex')) compareTypes( sink, - [ - { type: "uint8" }, - { type: "int8" }, - { type: "address" }, - { type: "uint256" }, - { type: "bytes7" }, - ], - [ - 1, - -2, - "0x1234567890123456789012345678901234567890", - 3n, - "0x1234567890abcd", - ] - ); - }); + [{ type: 'uint8' }, { type: 'int8' }, { type: 'address' }, { type: 'uint256' }, { type: 'bytes7' }], + [1, -2, '0x1234567890123456789012345678901234567890', 3n, '0x1234567890abcd'], + ) + }) - describe("string", () => { - it("short string", () => { - const sink = new Sink(1); - sink.offset(); - sink.string("hello"); - sink.endDynamic(); - compareTypes(sink, [{ type: "string" }], ["hello"]); - }); + describe('string', () => { + it('short string', () => { + const sink = new Sink(1) + sink.offset() + sink.string('hello') + sink.endDynamic() + compareTypes(sink, [{ type: 'string' }], ['hello']) + }) - it("32 byte string", () => { - const sink = new Sink(1); - sink.offset(); - sink.string("this string length is 32 bytes!!"); - sink.endDynamic(); - compareTypes( - sink, - [{ type: "string" }], - ["this string length is 32 bytes!!"] - ); - }); + it('32 byte string', () => { + const sink = new Sink(1) + sink.offset() + sink.string('this string length is 32 bytes!!') + sink.endDynamic() + compareTypes(sink, [{ type: 'string' }], ['this string length is 32 bytes!!']) + }) - it("longer string", () => { - const sink = new Sink(1); - sink.offset(); - sink.string("this string length is 33 bytes!!!"); - sink.endDynamic(); - compareTypes( - sink, - [{ type: "string" }], - ["this string length is 33 bytes!!!"] - ); - }); + it('longer string', () => { + const sink = new Sink(1) + sink.offset() + sink.string('this string length is 33 bytes!!!') + sink.endDynamic() + compareTypes(sink, [{ type: 'string' }], ['this string length is 33 bytes!!!']) + }) - it("UTF", () => { - const sink = new Sink(1); - sink.offset(); - sink.string("привет 👍"); - sink.endDynamic(); - compareTypes(sink, [{ type: "string" }], ["привет 👍"]); - }); - }); + it('UTF', () => { + const sink = new Sink(1) + sink.offset() + sink.string('привет 👍') + sink.endDynamic() + compareTypes(sink, [{ type: 'string' }], ['привет 👍']) + }) + }) - it("bytes", () => { - const sink = new Sink(1); - sink.offset(); - const buffer = Buffer.alloc(150); - buffer.fill("xd"); - sink.bytes(buffer); - sink.endDynamic(); - compareTypes(sink, [{ type: "bytes" }], [`0x${buffer.toString("hex")}`]); - }); -}); + it('bytes', () => { + const sink = new Sink(1) + sink.offset() + const buffer = Buffer.alloc(150) + buffer.fill('xd') + sink.bytes(buffer) + sink.endDynamic() + compareTypes(sink, [{ type: 'bytes' }], [`0x${buffer.toString('hex')}`]) + }) +}) diff --git a/evm/evm-codec/test/src.test.ts b/evm/evm-codec/test/src.test.ts index 9f472dfe1..4eb54cb6e 100644 --- a/evm/evm-codec/test/src.test.ts +++ b/evm/evm-codec/test/src.test.ts @@ -1,137 +1,121 @@ -import { describe, expect, it } from "vitest"; -import { Sink, Src } from "../src"; -import { encodeAbiParameters } from "viem"; +import { describe, expect, it } from 'vitest' +import { Sink, Src } from '../src' +import { encodeAbiParameters } from 'viem' -describe("src", () => { - it("negative numbers", () => { - const sink = new Sink(6); - sink.i8(-1); - sink.i16(-123); - sink.i32(-123456); - sink.i64(-1234567890n); - sink.i128(-12345678901234567890n); - sink.i256(-1234567890123456789012345678901234567890n); +describe('src', () => { + it('negative numbers', () => { + const sink = new Sink(6) + sink.i8(-1) + sink.i16(-123) + sink.i32(-123456) + sink.i64(-1234567890n) + sink.i128(-12345678901234567890n) + sink.i256(-1234567890123456789012345678901234567890n) - const src = new Src(sink.result()); - expect(src.i8()).toBe(-1); - expect(src.i16()).toBe(-123); - expect(src.i32()).toBe(-123456); - expect(src.i64()).toBe(-1234567890n); - expect(src.i128()).toBe(-12345678901234567890n); - expect(src.i256()).toBe(-1234567890123456789012345678901234567890n); - }); + const src = new Src(sink.result()) + expect(src.i8()).toBe(-1) + expect(src.i16()).toBe(-123) + expect(src.i32()).toBe(-123456) + expect(src.i64()).toBe(-1234567890n) + expect(src.i128()).toBe(-12345678901234567890n) + expect(src.i256()).toBe(-1234567890123456789012345678901234567890n) + }) - it("positive signed numbers", () => { - const sink = new Sink(6); - sink.i8(1); - sink.i16(123); - sink.i32(123456); - sink.i64(1234567890n); - sink.i128(12345678901234567890n); - sink.i256(1234567890123456789012345678901234567890n); + it('positive signed numbers', () => { + const sink = new Sink(6) + sink.i8(1) + sink.i16(123) + sink.i32(123456) + sink.i64(1234567890n) + sink.i128(12345678901234567890n) + sink.i256(1234567890123456789012345678901234567890n) - const src = new Src(sink.result()); - expect(src.i8()).toBe(1); - expect(src.i16()).toBe(123); - expect(src.i32()).toBe(123456); - expect(src.i64()).toBe(1234567890n); - expect(src.i128()).toBe(12345678901234567890n); - expect(src.i256()).toBe(1234567890123456789012345678901234567890n); - }); + const src = new Src(sink.result()) + expect(src.i8()).toBe(1) + expect(src.i16()).toBe(123) + expect(src.i32()).toBe(123456) + expect(src.i64()).toBe(1234567890n) + expect(src.i128()).toBe(12345678901234567890n) + expect(src.i256()).toBe(1234567890123456789012345678901234567890n) + }) - it("mixed static types", () => { - const sink = new Sink(4); - sink.u8(1); - sink.i8(-2); - sink.address("0x1234567890123456789012345678901234567890"); - sink.u256(3n); + it('mixed static types', () => { + const sink = new Sink(4) + sink.u8(1) + sink.i8(-2) + sink.address('0x1234567890123456789012345678901234567890') + sink.u256(3n) - const src = new Src(sink.result()); - expect(src.u8()).toBe(1); - expect(src.i8()).toBe(-2); - expect(src.address()).toBe("0x1234567890123456789012345678901234567890"); - expect(src.u256()).toBe(3n); - }); + const src = new Src(sink.result()) + expect(src.u8()).toBe(1) + expect(src.i8()).toBe(-2) + expect(src.address()).toBe('0x1234567890123456789012345678901234567890') + expect(src.u256()).toBe(3n) + }) - it("mixed dynamic types", () => { - const str1 = "abc".repeat(100); - const bytes1 = Buffer.alloc(100).fill("321"); - const bytes7 = "0x1234567890abcd"; - const str2 = "hello"; - const address = "0xabc4567890123456789012345678901234567890"; + it('mixed dynamic types', () => { + const str1 = 'abc'.repeat(100) + const bytes1 = Buffer.alloc(100).fill('321') + const bytes7 = '0x1234567890abcd' + const str2 = 'hello' + const address = '0xabc4567890123456789012345678901234567890' const encoded = Buffer.from( encodeAbiParameters( [ - { type: "uint8" }, - { type: "string" }, - { type: "bytes7" }, - { type: "int128" }, - { type: "bytes" }, - { type: "address" }, - { type: "string" }, + { type: 'uint8' }, + { type: 'string' }, + { type: 'bytes7' }, + { type: 'int128' }, + { type: 'bytes' }, + { type: 'address' }, + { type: 'string' }, ], - [ - 69, - str1, - bytes7, - -21312312452243312424534213123123123123n, - `0x${bytes1.toString("hex")}`, - address, - str2, - ] + [69, str1, bytes7, -21312312452243312424534213123123123123n, `0x${bytes1.toString('hex')}`, address, str2], ).slice(2), - "hex" - ); - const src = new Src(encoded); - expect(src.u8()).toBe(69); - expect(src.string()).toBe(str1); - expect(src.staticBytes(7)).toStrictEqual( - Buffer.from(bytes7.slice(2), "hex") - ); - expect(src.i128()).toBe(-21312312452243312424534213123123123123n); - expect(src.bytes()).toStrictEqual(bytes1); - expect(src.address()).toBe(address); - expect(src.string()).toBe(str2); - }); + 'hex', + ) + const src = new Src(encoded) + expect(src.u8()).toBe(69) + expect(src.string()).toBe(str1) + expect(src.staticBytes(7)).toStrictEqual(Buffer.from(bytes7.slice(2), 'hex')) + expect(src.i128()).toBe(-21312312452243312424534213123123123123n) + expect(src.bytes()).toStrictEqual(bytes1) + expect(src.address()).toBe(address) + expect(src.string()).toBe(str2) + }) - describe("string", () => { + describe('string', () => { function testString(str: string) { - const encoded = Buffer.from( - encodeAbiParameters([{ type: "string" }], [str]).slice(2), - "hex" - ); - const src = new Src(encoded); - expect(src.string()).toBe(str); + const encoded = Buffer.from(encodeAbiParameters([{ type: 'string' }], [str]).slice(2), 'hex') + const src = new Src(encoded) + expect(src.string()).toBe(str) } - it("short string", () => { - testString("hello"); - }); + it('short string', () => { + testString('hello') + }) - it("32 byte string", () => { - testString("this string length is 32 bytes!!"); - }); + it('32 byte string', () => { + testString('this string length is 32 bytes!!') + }) - it("longer string", () => { - testString("this string length is 33 bytes!!!"); - }); + it('longer string', () => { + testString('this string length is 33 bytes!!!') + }) - it("UTF", () => { - testString("привет 👍"); - }); - }); + it('UTF', () => { + testString('привет 👍') + }) + }) - it("bytes", () => { - const buffer = Buffer.alloc(150); - buffer.fill("xd"); + it('bytes', () => { + const buffer = Buffer.alloc(150) + buffer.fill('xd') const encoded = Buffer.from( - encodeAbiParameters( - [{ type: "bytes" }], - [`0x${buffer.toString("hex")}`] - ).slice(2), - "hex" - ); - const src = new Src(encoded); - expect(src.bytes()).toStrictEqual(buffer); - }); -}); + encodeAbiParameters([{ type: 'bytes' }], [`0x${buffer.toString('hex')}`]).slice(2), + 'hex', + ) + const src = new Src(encoded) + expect(src.bytes()).toStrictEqual(buffer) + }) +}) diff --git a/evm/evm-codec/test/struct.bench.ts b/evm/evm-codec/test/struct.bench.ts index 8cc8b9fb0..608ca7315 100644 --- a/evm/evm-codec/test/struct.bench.ts +++ b/evm/evm-codec/test/struct.bench.ts @@ -1,44 +1,44 @@ -import { bench, describe } from "vitest"; -import { address, array, Codec, Sink, Src, struct, uint256 } from "../src"; -import { decodeAbiParameters, encodeAbiParameters } from "viem"; -import { ethers } from "ethers"; +import { bench, describe } from 'vitest' +import { address, array, Codec, Sink, Src, struct, uint256 } from '../src' +import { decodeAbiParameters, encodeAbiParameters } from 'viem' +import { ethers } from 'ethers' -const hugeArray = Array.from({ length: 1000 }, (_, i) => BigInt(i)); +const hugeArray = Array.from({ length: 1000 }, (_, i) => BigInt(i)) class InlinedStructCodec< S extends { - a: bigint[]; - b: bigint; + a: bigint[] + b: bigint c: { - d: bigint[]; - e: string; - }; - } + d: bigint[] + e: string + } + }, > implements Codec { - isDynamic = true; + isDynamic = true public encode(sink: Sink, val: S): void { - sink.offset(); - const tempSink = new Sink(3); - array(uint256).encode(tempSink, val.a); - uint256.encode(tempSink, val.b); - sink.offset(); - const tempSink2 = new Sink(2); - array(uint256).encode(tempSink2, val.c.d); - address.encode(tempSink2, val.c.e); - tempSink.append(tempSink2); - tempSink.jumpBack(); - sink.append(tempSink); - sink.jumpBack(); + sink.offset() + const tempSink = new Sink(3) + array(uint256).encode(tempSink, val.a) + uint256.encode(tempSink, val.b) + sink.offset() + const tempSink2 = new Sink(2) + array(uint256).encode(tempSink2, val.c.d) + address.encode(tempSink2, val.c.e) + tempSink.append(tempSink2) + tempSink.jumpBack() + sink.append(tempSink) + sink.jumpBack() } public decode(src: Src): S { - const offset = src.u32(); - const tmpSrc = src.slice(offset); - const decoded = [array(uint256).decode(tmpSrc), uint256.decode(tmpSrc)]; - const offset2 = tmpSrc.u32(); - const tmpSrc2 = tmpSrc.slice(offset2); - const decoded2 = [array(uint256).decode(tmpSrc2), address.decode(tmpSrc2)]; + const offset = src.u32() + const tmpSrc = src.slice(offset) + const decoded = [array(uint256).decode(tmpSrc), uint256.decode(tmpSrc)] + const offset2 = tmpSrc.u32() + const tmpSrc2 = tmpSrc.slice(offset2) + const decoded2 = [array(uint256).decode(tmpSrc2), address.decode(tmpSrc2)] return { a: decoded[0], b: decoded[1], @@ -46,7 +46,7 @@ class InlinedStructCodec< d: decoded2[0], e: decoded2[1], }, - } as S; + } as S } } @@ -54,49 +54,49 @@ const s = struct({ a: array(uint256), b: uint256, c: struct({ d: array(uint256), e: address }), -}); -const inlined = new InlinedStructCodec(); +}) +const inlined = new InlinedStructCodec() -describe("StructCodec - encoding", () => { - bench("encoding dynamic tuple", () => { - const sink1 = new Sink(1); +describe('StructCodec - encoding', () => { + bench('encoding dynamic tuple', () => { + const sink1 = new Sink(1) s.encode(sink1, { a: hugeArray, b: 2n, c: { d: hugeArray, - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); - }); + }) + }) - bench("inlined - encoding dynamic tuple", () => { - const sink2 = new Sink(1); + bench('inlined - encoding dynamic tuple', () => { + const sink2 = new Sink(1) inlined.encode(sink2, { a: hugeArray, b: 2n, c: { d: hugeArray, - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); - }); + }) + }) - bench("viem - encoding dynamic tuple", () => { + bench('viem - encoding dynamic tuple', () => { encodeAbiParameters( [ { - type: "tuple", + type: 'tuple', components: [ - { name: "a", type: "uint256[]" }, - { name: "b", type: "uint256" }, + { name: 'a', type: 'uint256[]' }, + { name: 'b', type: 'uint256' }, { - name: "c", - type: "tuple", + name: 'c', + type: 'tuple', components: [ - { name: "d", type: "uint256[]" }, - { name: "e", type: "address" }, + { name: 'd', type: 'uint256[]' }, + { name: 'e', type: 'address' }, ], }, ], @@ -108,76 +108,73 @@ describe("StructCodec - encoding", () => { b: 2n, c: { d: hugeArray, - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, }, - ] - ); - }); + ], + ) + }) - bench("ethers - encoding dynamic tuple", () => { + bench('ethers - encoding dynamic tuple', () => { ethers.utils.defaultAbiCoder.encode( - ["tuple(uint256[] a,uint256 b,tuple(uint256[] d,address e) c)"], + ['tuple(uint256[] a,uint256 b,tuple(uint256[] d,address e) c)'], [ { a: hugeArray, b: 2n, c: { d: hugeArray, - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, }, - ] - ); - }); -}); + ], + ) + }) +}) -describe("StructCodec - decoding", () => { - const sink = new Sink(1); +describe('StructCodec - decoding', () => { + const sink = new Sink(1) s.encode(sink, { a: hugeArray, b: 2n, c: { d: hugeArray, - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); + }) - bench("decoding dynamic tuple", () => { - s.decode(new Src(sink.result())); - }); + bench('decoding dynamic tuple', () => { + s.decode(new Src(sink.result())) + }) - bench("inlined - decoding dynamic tuple", () => { - inlined.decode(new Src(sink.result())); - }); + bench('inlined - decoding dynamic tuple', () => { + inlined.decode(new Src(sink.result())) + }) - bench("viem - decoding dynamic tuple", () => { + bench('viem - decoding dynamic tuple', () => { decodeAbiParameters( [ { - type: "tuple", + type: 'tuple', components: [ - { name: "a", type: "uint256[]" }, - { name: "b", type: "uint256" }, + { name: 'a', type: 'uint256[]' }, + { name: 'b', type: 'uint256' }, { - name: "c", - type: "tuple", + name: 'c', + type: 'tuple', components: [ - { name: "d", type: "uint256[]" }, - { name: "e", type: "address" }, + { name: 'd', type: 'uint256[]' }, + { name: 'e', type: 'address' }, ], }, ], }, ], - sink.result() - ); - }); + sink.result(), + ) + }) - bench("ethers - decoding dynamic tuple", () => { - ethers.utils.defaultAbiCoder.decode( - ["tuple(uint256[] a,uint256 b,tuple(uint256[] d,address e) c)"], - sink.result() - ); - }); -}); + bench('ethers - decoding dynamic tuple', () => { + ethers.utils.defaultAbiCoder.decode(['tuple(uint256[] a,uint256 b,tuple(uint256[] d,address e) c)'], sink.result()) + }) +}) diff --git a/evm/evm-codec/test/struct.test.ts b/evm/evm-codec/test/struct.test.ts index ae36948f3..de9816742 100644 --- a/evm/evm-codec/test/struct.test.ts +++ b/evm/evm-codec/test/struct.test.ts @@ -1,49 +1,40 @@ -import { describe, expect, it } from "vitest"; -import { AbiParameter, encodeAbiParameters } from "viem"; -import { - address, - array, - bytes4, - int8, - Sink, - Src, - struct, - uint256, -} from "../src"; +import { describe, expect, it } from 'vitest' +import { AbiParameter, encodeAbiParameters } from 'viem' +import { address, array, bytes4, int8, Sink, Src, struct, uint256 } from '../src' function compareTypes(sink: Sink, types: AbiParameter[], values: any[]) { - expect(sink.toString()).toEqual(encodeAbiParameters(types, values)); + expect(sink.toString()).toEqual(encodeAbiParameters(types, values)) } -describe("StructCodec", () => { - it("static tuple", () => { +describe('StructCodec', () => { + it('static tuple', () => { const s = struct({ a: int8, b: uint256, c: struct({ e: address }), - }); + }) - const sink = new Sink(3); + const sink = new Sink(3) s.encode(sink, { a: 1, b: 2n, c: { - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); + }) compareTypes( sink, [ { - type: "tuple", + type: 'tuple', components: [ - { name: "a", type: "int8" }, - { name: "b", type: "uint256" }, + { name: 'a', type: 'int8' }, + { name: 'b', type: 'uint256' }, { - name: "c", - type: "tuple", - components: [{ name: "e", type: "address" }], + name: 'c', + type: 'tuple', + components: [{ name: 'e', type: 'address' }], }, ], }, @@ -54,50 +45,50 @@ describe("StructCodec", () => { b: 2n, c: { d: [3n, 4n], - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, }, - ] - ); + ], + ) expect(s.decode(new Src(sink.result()))).toStrictEqual({ a: 1, b: 2n, c: { - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); - }); + }) + }) - it("dynamic tuple", () => { + it('dynamic tuple', () => { const s = struct({ a: array(uint256), b: uint256, c: struct({ d: array(uint256), e: address }), - }); + }) - const sink = new Sink(1); + const sink = new Sink(1) s.encode(sink, { a: [100n, 1n, 123n], b: 2n, c: { d: [3n, 4n], - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); + }) compareTypes( sink, [ { - type: "tuple", + type: 'tuple', components: [ - { name: "a", type: "uint256[]" }, - { name: "b", type: "uint256" }, + { name: 'a', type: 'uint256[]' }, + { name: 'b', type: 'uint256' }, { - name: "c", - type: "tuple", + name: 'c', + type: 'tuple', components: [ - { name: "d", type: "uint256[]" }, - { name: "e", type: "address" }, + { name: 'd', type: 'uint256[]' }, + { name: 'e', type: 'address' }, ], }, ], @@ -109,30 +100,30 @@ describe("StructCodec", () => { b: 2n, c: { d: [3n, 4n], - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, }, - ] - ); + ], + ) expect(s.decode(new Src(sink.result()))).toStrictEqual({ a: [100n, 1n, 123n], b: 2n, c: { d: [3n, 4n], - e: "0x1234567890123456789012345678901234567890", + e: '0x1234567890123456789012345678901234567890', }, - }); - }); + }) + }) - it("dynamic tuple2", () => { + it('dynamic tuple2', () => { const s = struct({ foo: uint256, bar: array(uint256), str: struct({ foo: uint256, bar: bytes4 }), - }); + }) - const sink = new Sink(1); + const sink = new Sink(1) s.encode(sink, { foo: 100n, bar: [1n, 2n, 3n], @@ -140,21 +131,21 @@ describe("StructCodec", () => { foo: 123n, bar: Uint8Array.from([0x12, 0x34, 0x56, 0x78]), }, - }); + }) compareTypes( sink, [ { - type: "tuple", + type: 'tuple', components: [ - { name: "foo", type: "uint256" }, - { name: "bar", type: "uint256[]" }, + { name: 'foo', type: 'uint256' }, + { name: 'bar', type: 'uint256[]' }, { - name: "str", - type: "tuple", + name: 'str', + type: 'tuple', components: [ - { name: "foo", type: "uint256" }, - { name: "bar", type: "bytes4" }, + { name: 'foo', type: 'uint256' }, + { name: 'bar', type: 'bytes4' }, ], }, ], @@ -166,11 +157,11 @@ describe("StructCodec", () => { bar: [1n, 2n, 3n], str: { foo: 123n, - bar: "0x12345678", + bar: '0x12345678', }, }, - ] - ); + ], + ) expect(s.decode(new Src(sink.result()))).toStrictEqual({ foo: 100n, @@ -179,6 +170,6 @@ describe("StructCodec", () => { foo: 123n, bar: Buffer.from([0x12, 0x34, 0x56, 0x78]), }, - }); - }); -}); + }) + }) +}) diff --git a/evm/evm-codec/tsconfig.json b/evm/evm-codec/tsconfig.json index 02e7ec06d..845192ba7 100644 --- a/evm/evm-codec/tsconfig.json +++ b/evm/evm-codec/tsconfig.json @@ -15,7 +15,5 @@ "skipLibCheck": true }, "include": ["src", "test"], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] }