From 7e99408c6d74f5e66daf7266f7f953a2cae2a9cd Mon Sep 17 00:00:00 2001 From: allen Date: Mon, 15 Aug 2022 03:09:43 +0800 Subject: [PATCH] refactor: new abi re #77 --- .eslintrc.js | 8 +- .nycrc | 4 +- package.json | 2 +- src/abi/abi.ts | 611 +++++ src/abi/abicoder.ts | 107 + src/abi/coder/address.ts | 23 + src/abi/coder/array.ts | 76 + src/abi/coder/boolean.ts | 20 + src/abi/coder/bytes.ts | 61 + src/abi/coder/common.ts | 171 -- src/abi/coder/dynamic.ts | 92 - src/abi/coder/gid.ts | 24 + src/abi/coder/index.ts | 481 ++-- src/abi/coder/null.ts | 23 + src/abi/coder/number.ts | 56 + src/abi/coder/string.ts | 20 + src/abi/coder/tokenId.ts | 23 + src/abi/coder/tuple.ts | 76 + src/abi/encodeFunction.ts | 47 - src/abi/fragments.ts | 1231 ++++++++++ src/abi/index.ts | 221 +- src/abi/inputsType.ts | 118 - src/abi/utils.ts | 178 ++ src/accountBlock/utils.ts | 28 +- src/utils/index.ts | 25 +- test/RPC/dex.js | 14 +- test/RPC/wallet.js | 44 +- test/packages/abi.js | 3310 +++++++++++++++++---------- test/packages/accountBlock/utils.js | 4 +- test/packages/utils.js | 192 +- test/packages/viteAPI/index.js | 30 +- 31 files changed, 5234 insertions(+), 2086 deletions(-) create mode 100644 src/abi/abi.ts create mode 100644 src/abi/abicoder.ts create mode 100644 src/abi/coder/address.ts create mode 100644 src/abi/coder/array.ts create mode 100644 src/abi/coder/boolean.ts create mode 100644 src/abi/coder/bytes.ts delete mode 100644 src/abi/coder/common.ts delete mode 100644 src/abi/coder/dynamic.ts create mode 100644 src/abi/coder/gid.ts create mode 100644 src/abi/coder/null.ts create mode 100644 src/abi/coder/number.ts create mode 100644 src/abi/coder/string.ts create mode 100644 src/abi/coder/tokenId.ts create mode 100644 src/abi/coder/tuple.ts delete mode 100644 src/abi/encodeFunction.ts create mode 100644 src/abi/fragments.ts delete mode 100644 src/abi/inputsType.ts create mode 100644 src/abi/utils.ts diff --git a/.eslintrc.js b/.eslintrc.js index 16041e89..fcc75884 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,10 +4,12 @@ module.exports = { '@typescript-eslint' ], 'env': { + 'es2020': true, 'browser': true, 'commonjs': true, - 'es6': true, - 'node': true + // 'es6': true, + 'node': true, + 'mocha': true }, 'parserOptions': { 'ecmaFeatures': {'jsx': true}, @@ -29,7 +31,7 @@ module.exports = { 'guard-for-in': 'off', 'no-throw-literal': 'off', 'prefer-promise-reject-errors': 'off', - 'eqeqeq': 'error', + 'eqeqeq': [ 'error', 'smart' ], 'no-else-return': 'error', 'no-labels': 'error', 'no-return-assign': 'error', diff --git a/.nycrc b/.nycrc index 4ae6baaf..813f7291 100644 --- a/.nycrc +++ b/.nycrc @@ -15,6 +15,6 @@ "html", "text" ], - "sourceMap": false, + "sourceMap": true, "instrument": true -} \ No newline at end of file +} diff --git a/package.json b/package.json index d923342b..37750c30 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "html", "text" ], - "sourceMap": false, + "sourceMap": true, "instrument": true } } diff --git a/src/abi/abi.ts b/src/abi/abi.ts new file mode 100644 index 00000000..f3d7739d --- /dev/null +++ b/src/abi/abi.ts @@ -0,0 +1,611 @@ +import { AbiCoder, defaultAbiCoder } from './abicoder'; +import { Result } from './coder'; +import { + ConstructorFragment, + EventFragment, + FormatTypes, + Fragment, + FragmentType, + FunctionFragment, + FunctionLike, + JsonFragment, + JsonParamType, + OffchainFragment, + ParamType +} from './fragments'; +import { + blake2bHex, + isHexString, + isObject +} from '~@vite/vitejs-utils'; +import { arrayify, getArrayDepth, hexlify, rightPadZero, safeParseJson } from './utils'; + +export { Result }; + +function checkNames(fragment: Fragment, type: 'input' | 'output', params: Array): void { + params.reduce((accum, param) => { + if (param.name) { + if (accum[param.name]) { + throw new Error(`duplicate ${ type } parameter ${ JSON.stringify(param.name) } in ${ fragment.format(FormatTypes.Full) }`); + } + accum[param.name] = true; + } + return accum; + }, { }); +} + +export class Abi { + static from(fragments: string | Fragment | JsonFragment | Array): Abi { + return new Abi(fragments); + } + + static getAbiCoder(): AbiCoder { + return defaultAbiCoder; + } + + static getSighash(fragment: FunctionLike): string { + return blake2bHex(fragment.format(), null, 32).slice(0, 8); + } + + static getEventTopic(eventFragment: EventFragment): string { + return blake2bHex(eventFragment.format(), null, 32); + } + + private static _getFunctionLike(nameOrSighash?: string, _fragments?: { [name: string]: FunctionLike }): FunctionLike { + if (!nameOrSighash) { + if (Object.keys(_fragments).length !== 1) { + throw new Error('param(s) missing, methodName or signature or sighash.'); + } + return _fragments[Object.keys(_fragments)[0]]; + } + + if (isHexString(nameOrSighash)) { // sighash + for (const name in _fragments) { + if (nameOrSighash === Abi.getSighash(_fragments[name])) { + return _fragments[name]; + } + } + throw new Error(`no matching sighash: ${ nameOrSighash }`); + } + + // It is a bare name, look up the function (will return null if ambiguous) + if (nameOrSighash.indexOf('(') === -1) { + const name = nameOrSighash.trim(); + const matching = Object.keys(_fragments).filter(e => + (e.split('(')[0] === (_fragments[e].type === FragmentType.Callback ? `${ name }Callback` : name))); + if (matching.length === 0) { + throw new Error(`no matching function: ${ name }`); + } else if (matching.length > 1) { + throw new Error(`multiple matching functions: ${ name }`); + } + + return _fragments[matching[0]]; + } + + return undefined; + } + + readonly fragments: ReadonlyArray; + readonly events: { [ name: string ]: EventFragment }; + readonly functions: { [ name: string ]: FunctionFragment }; + readonly offchains: { [ name: string ]: OffchainFragment }; + readonly others: { [ name: string ]: Fragment }; + readonly deploy: ConstructorFragment; + + readonly _abiCoder: AbiCoder; + + protected constructor(fragments: string | Fragment | JsonFragment | Array) { + let abi: ReadonlyArray; + + const jsonParam: JsonParamType = safeParseJson(fragments); + if (jsonParam) { + fragments = jsonParam; + } + + if (!Array.isArray(fragments)) { + fragments = [fragments]; + } + abi = fragments; + + this.fragments = abi.map(fragment => Fragment.from(fragment)).filter(fragment => (fragment != null)); + this._abiCoder = Abi.getAbiCoder(); + this.functions = { }; + this.offchains = { }; + this.events = { }; + this.others = { }; + + // Add all fragments by their signature + this.fragments.forEach(fragment => { + let bucket: { [ name: string ]: Fragment } = null; + switch (fragment.type) { + case FragmentType.Constructor: + if (this.deploy) { + console.warn('duplicate definition - constructor'); + return; + } + checkNames(fragment, 'input', fragment.inputs); + Object.defineProperty(this, 'deploy', { + enumerable: true, + value: fragment as ConstructorFragment, + writable: false + }); + return; + case FragmentType.Function: + case FragmentType.Callback: + checkNames(fragment, 'input', fragment.inputs); + checkNames(fragment, 'output', (fragment as FunctionFragment).outputs); + bucket = this.functions; + break; + case FragmentType.Offchain: + checkNames(fragment, 'input', fragment.inputs); + checkNames(fragment, 'output', (fragment as OffchainFragment).outputs); + bucket = this.offchains; + break; + case FragmentType.Event: + checkNames(fragment, 'input', fragment.inputs); + bucket = this.events; + break; + case FragmentType.Variable: + case FragmentType.Fallback: + case FragmentType.Receive: + checkNames(fragment, 'input', fragment.inputs); + bucket = this.others; + break; + default: + return; + } + + const signature = fragment.format(); + if (bucket[signature]) { + console.warn(`duplicate definition - ${ signature }`); + return; + } + + bucket[signature] = fragment; + }); + + // If we do not have a constructor add a default + if (!this.deploy) { + this.deploy = ConstructorFragment.from({ + payable: false, + type: 'constructor' + }); + } + } + + /** + * Format the ABI interface + * @param format + */ + format(format?: FormatTypes): string | Array { + if (!format) { + format = FormatTypes.Full; + } + if (format === FormatTypes.Sighash) { + throw new Error('interface does not support formatting sighash'); + } + + const abi = this.fragments.map(fragment => fragment.format(format)); + + if (format === FormatTypes.Json) { + return JSON.stringify(abi.map(j => JSON.parse(j))); + } + + return abi; + } + + /** + * Find a function by function name, signature or sighash + * @param nameOrSignatureOrSighash + */ + getFunction(nameOrSignatureOrSighash?: string): FunctionFragment { + let result: FunctionFragment = Abi._getFunctionLike(nameOrSignatureOrSighash, this.functions) as FunctionFragment; + if (result) { + return result; + } + + // Normalize the signature and lookup the function + result = this.functions[FunctionFragment.fromString(nameOrSignatureOrSighash).format()]; + if (!result) { + throw new Error(`no matching function signature: ${ nameOrSignatureOrSighash }`); + } + return result; + } + + /** + * Find an offchain method by method name, signature or sighash (0.4.x) + * @param nameOrSignatureOrSighash + */ + getOffchain(nameOrSignatureOrSighash?: string): OffchainFragment { + let result: OffchainFragment = Abi._getFunctionLike(nameOrSignatureOrSighash, this.offchains) as OffchainFragment; + if (result) { + return result; + } + + // Normalize the signature and lookup the function + result = this.offchains[OffchainFragment.fromString(nameOrSignatureOrSighash).format()]; + if (!result) { + throw new Error(`no matching offchain signature: ${ nameOrSignatureOrSighash }`); + } + return result; + } + + /** + * Find an event by event name, signature or topic (non-anonymous) + * @param nameOrSignatureOrTopic + */ + getEvent(nameOrSignatureOrTopic?: string): EventFragment { + if (!nameOrSignatureOrTopic) { + if (Object.keys(this.events).length !== 1) { + throw new Error('[Error] Param(s) missing, eventName or signature or topic.'); + } + return this.events[Object.keys(this.events)[0]]; + } + + if (isHexString(nameOrSignatureOrTopic)) { + const topichash = nameOrSignatureOrTopic.toLowerCase(); + for (const name in this.events) { + if (topichash === this.getEventTopic(name)) { + return this.events[name]; + } + } + throw new Error(`no matching topichash: ${ topichash }`); + } + + // It is a bare name, look up the function (will return null if ambiguous) + if (nameOrSignatureOrTopic.indexOf('(') === -1) { + const name = nameOrSignatureOrTopic.trim(); + const matching = Object.keys(this.events).filter(f => (f.split('(')[0] === name)); + if (matching.length === 0) { + throw new Error(`no matching event: ${ name }`); + } else if (matching.length > 1) { + throw new Error(`multiple matching events: ${ name }`); + } + + return this.events[matching[0]]; + } + + // Normalize the signature and lookup the function + const result = this.events[EventFragment.fromString(nameOrSignatureOrTopic).format()]; + if (!result) { + throw new Error(`no matching event signature: ${ nameOrSignatureOrTopic }`); + } + return result; + } + + /** + * Get a function's sighash (the first 4 bytes of the 32-byte blake2b hash of the function signature) + * @param fragment Fragment of a function or an offchain method + */ + getSighash(fragment: FunctionFragment | string): string { + return Abi.getSighash(this._getFunction(fragment)); + } + + /** + * Get the topic of an event (the 32-byte blake2b hash) + * @param eventFragment + */ + getEventTopic(eventFragment: EventFragment | string): string { + return Abi.getEventTopic(this._getEvent(eventFragment)); + } + + /** + * Encode the data for constructor + * @param values + */ + encodeDeploy(values?: ReadonlyArray): string { + if (Object.keys(this.deploy.inputs).length === 0) { + throw new Error('abi has no constructor'); + } + + return this._encodeParams(this.deploy.inputs, values || [ ]); + } + + /** + * Decode the data from a function call (e.g. tx.data) + * @param functionFragment - Function fragment or sighash or name + * @param data + */ + decodeFunctionData(functionFragment: FunctionFragment | string, data: Buffer | string): Result { + const _fragment = this._getFunction(functionFragment); + + const bytes = arrayify(data); + + if (hexlify(bytes.slice(0, 4)) !== this.getSighash(_fragment)) { + throw new Error(`data signature does not match function ${ _fragment.name }: ${ hexlify(bytes.slice(0, 4)) }`); + } + + return this._decodeParams(_fragment.inputs, bytes.slice(4)); + } + + /** + * Encode the data for a function call (e.g. tx.data) + * @param functionFragment + * @param values + */ + encodeFunctionData(functionFragment: FunctionFragment | string, values?: ReadonlyArray): string { + const _fragment = this._getFunction(functionFragment); + + return hexlify(Abi.getSighash(_fragment).concat(this._encodeParams(_fragment.inputs, values || [ ]))); + } + + /** + * Decode the result from a view function call + * @param functionFragment Function fragment or method name or sighash or signature + * @param data Hex-string data or byte array + */ + decodeFunctionResult(functionFragment: FunctionFragment | string, data: Buffer | string): Result { + const _fragment = this._getFunction(functionFragment); + + const bytes = arrayify(data); + + if (bytes.length % this._abiCoder._getWordSize() === 0) { + return this._abiCoder.decode(_fragment.outputs, bytes); + } + + throw new Error(`decode function output failed: ${ _fragment }`); + } + + /** + * Encode the result for a view function call + * @param functionFragment Function fragment or method name or sighash or signature + * @param values Input arguments + */ + encodeFunctionResult(functionFragment: FunctionFragment | string, values?: ReadonlyArray): string { + const _fragment = this._getFunction(functionFragment); + + return hexlify(this._abiCoder.encode(_fragment.outputs, values || [ ])); + } + + /** + * Encode the data for calling an offchain method (e.g. tx.data) in 0.4.x + * @param offchainFragment Offchain fragment or method name or sighash or signature + * @param values Input arguments + */ + encodeOffchainData(offchainFragment: OffchainFragment | string, values?: ReadonlyArray): string { + const _fragment = this._getOffchain(offchainFragment); + + return hexlify(Abi.getSighash(_fragment).concat(this._encodeParams(_fragment.inputs, values || [ ]))); + } + + /** + * Decode the result from an offchain method call in 0.4.x + * @param offchainFragment Offchain fragment or method name or sighash or signature + * @param data Hex-string data or byte array + */ + decodeOffchainResult(offchainFragment: OffchainFragment | string, data: Buffer | string): Result { + const _fragment = this._getOffchain(offchainFragment); + + const bytes = arrayify(data); + + if (bytes.length % this._abiCoder._getWordSize() === 0) { + return this._abiCoder.decode(_fragment.outputs, bytes); + } + + throw new Error(`decode offchain output failed: ${ _fragment }`); + } + + /** + * Create the filter for the event with search criteria (e.g. for ledger_getVmLogsByFilter) + * @param eventFragment + * @param values Array of topics or topic arrays + */ + encodeFilterTopics(eventFragment: EventFragment | string, values: ReadonlyArray): Array> { + const _fragment = this._getEvent(eventFragment); + + if (values.length > _fragment.inputs.length) { + throw new Error(`too many arguments for ${ _fragment.format() }: ${ values }`); + } + + const topics: Array> = []; + if (!_fragment.anonymous) { + topics.push(this.getEventTopic(_fragment)); + } + + const encodeTopic = (param: ParamType, value: any, _isSubElement?: boolean): string => { + if (param.type === 'string') { + if (_isSubElement) { + return rightPadZero(Buffer.from(value, 'utf8'), 32); + } + return blake2bHex(value, null, 32); + } else if (param.type === 'bytes') { + if (_isSubElement) { + return rightPadZero(value, 32); + } + return blake2bHex((value), null, 32); + } else if (param.baseType === 'tuple') { + if (!isObject(value)) { + throw new Error(`type error, expect object but got ${ typeof value }`); + } + const result = param.components.reduce((accum, item) => accum.concat(encodeTopic(item, value[item.name], true)), ''); + if (_isSubElement) { + return result; + } + return blake2bHex(arrayify(result), null, 32); + } else if (param.baseType === 'array') { + if (!Array.isArray(value)) { + throw new Error(`type error, expect array but got ${ typeof value }`); + } + // /**EXPERIMENTAL FEATURE**/ + // using arrays (esp. dynamic arrays) as an indexed topic may cause wrong results at the moment + // if an array must be used, use static array + const result = value.reduce((accum, item) => accum.concat(encodeTopic(param.arrayChildren, item, true)), ''); + if (_isSubElement) { + return result; + } + return blake2bHex(arrayify(result), null, 32); + } + return this._abiCoder.encode([param.type], [value]); + }; + // only get indexed inputs + const _inputs = _fragment.inputs.filter(item => item.indexed); + values.forEach((value, index) => { + const param = _inputs[index]; + + if (!param.indexed) { + return; + } + + if (value == null) { + topics.push(null); + } else if (Array.isArray(value) && (param.baseType !== 'array' || getArrayDepth(value) > param.arrayDimension)) { // search for multiple results + if (getArrayDepth(value) > 1 + param.arrayDimension) { + throw new Error(`incorrect filter format, expected input depth: ${ 1 + param.arrayDimension }, actual: ${ getArrayDepth(value) }`); + } + topics.push(value.map(value => encodeTopic(param, value))); + } else { + topics.push(encodeTopic(param, value)); + } + }); + + // Trim off trailing nulls + while (topics.length && topics[topics.length - 1] === null) { + topics.pop(); + } + + return topics; + } + + /** + * Encode an event log + * @param eventFragment + * @param values + */ + encodeEventLog(eventFragment: EventFragment | string, values: ReadonlyArray): { data: string, topics: Array } { + const _fragment = this._getEvent(eventFragment); + + const topics: Array = [ ]; + const dataTypes: Array = [ ]; + const dataValues: Array = [ ]; + + if (!_fragment.anonymous) { + topics.push(this.getEventTopic(_fragment)); + } + + if (values.length !== _fragment.inputs.length) { + throw new Error(`event arguments/values mismatch: ${ values }`); + } + + _fragment.inputs.forEach((param, index) => { + const value = values[index]; + if (param.indexed) { + if (param.type === 'string') { + topics.push(blake2bHex(value, null, 32)); + } else if (param.type === 'bytes') { + topics.push(blake2bHex(value, null, 32)); + } else if (param.baseType === 'tuple' || param.baseType === 'array') { + throw new Error('encoding event log for tuple or array is not implemented'); + } else { + topics.push(this._abiCoder.encode([param.type], [value])); + } + } else { + dataTypes.push(param); + dataValues.push(value); + } + }); + + return { + data: this._abiCoder.encode(dataTypes, dataValues), + topics: topics + }; + } + + /** + * Decode an event log according to data and topics + * @param eventFragment + * @param data + * @param topics + */ + decodeEventLog(eventFragment: EventFragment | string, data: Buffer | string, topics?: ReadonlyArray): {[key: string]: any} { + const _fragment = this._getEvent(eventFragment); + + if (topics != null && !_fragment.anonymous) { + const topicHash = this.getEventTopic(_fragment); + if (!isHexString(topics[0], 32) || topics[0].toLowerCase() !== topicHash) { + throw new Error(`fragment/topic mismatch, expected: ${ topicHash }, actual: ${ topics[0] }`); + } + topics = topics.slice(1); + } + + const indexed: Array = []; + const nonIndexed: Array = []; + + _fragment.inputs.forEach((param, index) => { + if (param.indexed) { + if (param.type === 'string' || param.type === 'bytes' || param.baseType === 'tuple' || param.baseType === 'array') { + indexed.push(ParamType.fromObject({ type: 'bytes32', name: param.name })); + } else { + indexed.push(param); + } + } else { + nonIndexed.push(param); + } + }); + + const resultIndexed = (!topics || topics.length === 0) ? null : this._abiCoder.decode(indexed, Buffer.concat(topics.map(item => arrayify(item)))); + const resultNonIndexed = this._abiCoder.decode(nonIndexed, data, true); + + const result = { }; + let nonIndexedIndex = 0, indexedIndex = 0; + _fragment.inputs.forEach((param, index) => { + if (param.indexed) { + if (resultIndexed == null) { + result[index] = null; + } else { + result[index] = resultIndexed[indexedIndex++]; + } + } else { + result[index] = resultNonIndexed[nonIndexedIndex++]; + } + + // Add the keyword argument if named and safe + if (param.name && result[param.name] == null) { + result[param.name] = result[index]; + } + }); + + return Object.freeze(result); + } + + private _decodeParams(params: ReadonlyArray, data: Buffer | string): Result { + return this._abiCoder.decode(params, data); + } + + private _encodeParams(params: ReadonlyArray, values: ReadonlyArray): string { + return this._abiCoder.encode(params, values); + } + + private _getFunction(functionFragment: FunctionFragment | string): FunctionFragment { + if (!functionFragment) { + functionFragment = this.getFunction(); + } + if (typeof (functionFragment) === 'string') { + functionFragment = this.getFunction(functionFragment); + } + + return functionFragment; + } + + private _getOffchain(functionFragment: OffchainFragment | string): OffchainFragment { + if (!functionFragment) { + functionFragment = this.getOffchain(); + } + if (typeof (functionFragment) === 'string') { + functionFragment = this.getOffchain(functionFragment); + } + + return functionFragment; + } + + private _getEvent(eventFragment: EventFragment | string): EventFragment { + if (!eventFragment) { + eventFragment = this.getEvent(); + } + if (typeof (eventFragment) === 'string') { + eventFragment = this.getEvent(eventFragment); + } + + return eventFragment; + } +} + diff --git a/src/abi/abicoder.ts b/src/abi/abicoder.ts new file mode 100644 index 00000000..d5bb06c3 --- /dev/null +++ b/src/abi/abicoder.ts @@ -0,0 +1,107 @@ +import { Coder, Reader, Result, Writer } from './coder'; +import { AddressCoder } from './coder/address'; +import { ArrayCoder } from './coder/array'; +import { BooleanCoder } from './coder/boolean'; +import { BytesCoder, FixedBytesCoder } from './coder/bytes'; +import { NullCoder } from './coder/null'; +import { NumberCoder } from './coder/number'; +import { StringCoder } from './coder/string'; +import { TupleCoder } from './coder/tuple'; +import { TokenIdCoder } from './coder/tokenId'; +import { GidCoder } from './coder/gid'; + +import { ParamType } from './fragments'; +import { arrayify } from './utils'; + +const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/); +const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/); + +export class AbiCoder { + _getCoder(param: ParamType): Coder { + switch (param.baseType) { + case 'address': + return new AddressCoder(param.name); + case 'tokenId': + return new TokenIdCoder(param.name); + case 'gid': + return new GidCoder(param.name); + case 'bool': + return new BooleanCoder(param.name); + case 'string': + return new StringCoder(param.name); + case 'bytes': + return new BytesCoder(param.name); + case 'array': + return new ArrayCoder(this._getCoder(param.arrayChildren), param.arrayLength, param.name); + case 'tuple': + return new TupleCoder((param.components || []).map(component => this._getCoder(component)), param.name); + case '': + return new NullCoder(param.name); + } + + // u?int[0-9]* + let match = param.type.match(paramTypeNumber); + if (match) { + const size = parseInt(match[2] || '256'); + if (size === 0 || size > 256 || (size % 8) !== 0) { + throw new Error(`invalid ${ match[1] } bit length, ${ param }`); + } + return new NumberCoder(size / 8, (match[1] === 'int'), param.name); + } + + // bytes[0-9]+ + match = param.type.match(paramTypeBytes); + if (match) { + const size = parseInt(match[1]); + if (size === 0 || size > 32) { + throw new Error(`invalid bytes length, ${ param }`); + } + return new FixedBytesCoder(size, param.name); + } + + throw new Error(`invalid type, ${ param.type }`); + } + + _getWordSize(): number { + return 32; + } + + _getReader(data: Buffer, allowLoose?: boolean): Reader { + return new Reader(data, this._getWordSize(), allowLoose); + } + + _getWriter(): Writer { + return new Writer(this._getWordSize()); + } + + getDefaultValue(types: ReadonlyArray): Result { + const coders: Array = types.map(type => this._getCoder(ParamType.from(type))); + const coder = new TupleCoder(coders, '_'); + return coder.defaultValue(); + } + + encode(types: ReadonlyArray, values: ReadonlyArray): string { + if (typeof (values) === 'string') { + values = JSON.parse(values); + } + if (types.length !== values.length) { + throw new Error(`types/values length mismatch, types: ${ types.length }, values: ${ values.length }`); + } + + const coders = types.map(type => this._getCoder(ParamType.from(type))); + const coder = new TupleCoder(coders, '_'); + + const writer = this._getWriter(); + coder.encode(writer, values); + return writer.data; + } + + decode(types: ReadonlyArray, data: Buffer | string, loose?: boolean): Result { + const coders: Array = types.map(type => this._getCoder(ParamType.from(type))); + const coder = new TupleCoder(coders, '_'); + return coder.decode(this._getReader(arrayify(data), loose)); + } +} + +export const defaultAbiCoder: AbiCoder = new AbiCoder(); + diff --git a/src/abi/coder/address.ts b/src/abi/coder/address.ts new file mode 100644 index 00000000..05729722 --- /dev/null +++ b/src/abi/coder/address.ts @@ -0,0 +1,23 @@ +import { Coder, Reader, Writer } from './index'; +import { getAddressFromOriginalAddress, getOriginalAddressFromAddress } from '~@vite/vitejs-wallet/address'; +import { leftPadZero } from '../utils'; + +export class AddressCoder extends Coder { + constructor(localName: string) { + super('address', 'address', localName, false); + } + + defaultValue(): string { + return getAddressFromOriginalAddress('000000000000000000000000000000000000000000'); + } + + encode(writer: Writer, value: string): number { + value = getOriginalAddressFromAddress(value); + return writer.writeValue(value); + } + + decode(reader: Reader): any { + return getAddressFromOriginalAddress(leftPadZero(reader.readValue().toString(16), 21)); + } +} + diff --git a/src/abi/coder/array.ts b/src/abi/coder/array.ts new file mode 100644 index 00000000..093588e3 --- /dev/null +++ b/src/abi/coder/array.ts @@ -0,0 +1,76 @@ +import { Coder, Reader, Writer } from './index'; + +export class ArrayCoder extends Coder { + readonly coder: Coder; + readonly length: number; + + constructor(coder: Coder, length: number, localName: string) { + const type = (`${ coder.type }[${ length >= 0 ? length : '' }]`); + const dynamic = (length === -1 || coder.dynamic); + super('array', type, localName, dynamic); + + this.coder = coder; + this.length = length; + } + + defaultValue(): Array { + // Verifies the child coder is valid (even if the array is dynamic or 0-length) + const defaultChild = this.coder.defaultValue(); + + const result: Array = []; + for (let i = 0; i < this.length; i++) { + result.push(defaultChild); + } + return result; + } + + encode(writer: Writer, value: Array): number { + if (typeof (value) === 'string') { + value = JSON.parse(value); + } + if (!Array.isArray(value)) { + throw new Error(`expected array value: ${ value }`); + } + + let count = this.length; + + if (count === -1) { // encode dynamic array length + count = value.length; + writer.writeValue(value.length); + } + + if (value.length !== count) { + throw new Error(`array value and size mismatch: ${ value }, size: ${ count }`); + } + + const coders = []; + for (let i = 0; i < value.length; i++) { + coders.push(this.coder); + } + + return this.pack(writer, coders, value); + } + + decode(reader: Reader): any { + let count = this.length; + if (count === -1) { + count = reader.readValue().toNumber(); + + // Check that there is *roughly* enough data to ensure + // stray random data is not being read as a length. Each + // slot requires at least 32 bytes for their value (or 32 + // bytes as a link to the data). This could use a much + // tighter bound, but we are erroring on the side of safety. + if (count * 32 > reader._data.length) { + throw new Error(`insufficient data length: ${ reader._data.length }, count: ${ count }`); + } + } + const coders = []; + for (let i = 0; i < count; i++) { + coders.push(this.coder); + } + + return reader.coerce(this, this.unpack(reader, coders)); + } +} + diff --git a/src/abi/coder/boolean.ts b/src/abi/coder/boolean.ts new file mode 100644 index 00000000..164d16b5 --- /dev/null +++ b/src/abi/coder/boolean.ts @@ -0,0 +1,20 @@ +import { Coder, Reader, Writer } from './index'; + +export class BooleanCoder extends Coder { + constructor(localName: string) { + super('bool', 'bool', localName, false); + } + + defaultValue(): boolean { + return false; + } + + encode(writer: Writer, value: boolean): number { + return writer.writeValue(value ? 1 : 0); + } + + decode(reader: Reader): any { + return reader.coerce(this, !reader.readValue().isZero()); + } +} + diff --git a/src/abi/coder/bytes.ts b/src/abi/coder/bytes.ts new file mode 100644 index 00000000..6edac24a --- /dev/null +++ b/src/abi/coder/bytes.ts @@ -0,0 +1,61 @@ +import { Coder, Reader, Writer } from './index'; +import { arrayify, hexlify } from '../utils'; + +export class DynamicBytesCoder extends Coder { + constructor(type: string, localName: string) { + super(type, type, localName, true); + } + + defaultValue(): string { + return ''; + } + + encode(writer: Writer, value: any): number { + value = arrayify(value); + let length = writer.writeValue(value.length); + length += writer.writeBytes(value); + return length; + } + + decode(reader: Reader): any { + return reader.readBytes(reader.readValue().toNumber(), true); + } +} + +export class BytesCoder extends DynamicBytesCoder { + constructor(localName: string) { + super('bytes', localName); + } + + decode(reader: Reader): any { + return reader.coerce(this, hexlify(super.decode(reader))); + } +} + +export class FixedBytesCoder extends Coder { + readonly size: number; + + constructor(size: number, localName: string) { + const name = `bytes${ String(size) }`; + super(name, name, localName, false); + this.size = size; + } + + defaultValue(): string { + return ('0000000000000000000000000000000000000000000000000000000000000000').substring(0, this.size * 2); + } + + encode(writer: Writer, value: Buffer | string): number { + const data = arrayify(value); + if (data.length !== this.size) { + throw new Error(`incorrect data length: ${ value }`); + } + return writer.writeBytes(data); + } + + decode(reader: Reader): any { + return reader.coerce(this, hexlify(reader.readBytes(this.size))); + } +} + + diff --git a/src/abi/coder/common.ts b/src/abi/coder/common.ts deleted file mode 100644 index e2497348..00000000 --- a/src/abi/coder/common.ts +++ /dev/null @@ -1,171 +0,0 @@ -// address bool gid number - -const BigNumber = require('bn.js'); - -import { unsafeInteger, integerIllegal } from '~@vite/vitejs-error'; -import { getAddressFromOriginalAddress, getOriginalAddressFromAddress } from '~@vite/vitejs-wallet/address'; -import { getOriginalTokenIdFromTokenId, getTokenIdFromOriginalTokenId, isSafeInteger } from '~@vite/vitejs-utils'; - - -export function encode(typeObj, params) { - const Bytes_Data = getBytesData(typeObj, params); - return encodeBytesData(typeObj, Bytes_Data); -} - -export function encodeBytesData(typeObj, Bytes_Data) { - const Byte_Len = typeObj.byteLength; - const Offset = Byte_Len - Bytes_Data.length; - if (Offset < 0) { - throw lengthError(typeObj, Bytes_Data.length, 'Offset < 0'); - } - - const result = new Uint8Array(Byte_Len); - result.set(Bytes_Data, typeObj.type === 'bytes' ? 0 : Offset); - - return { - result: Buffer.from(result).toString('hex'), - typeObj - }; -} - -export function decodeToHexData(typeObj, params) { - if (typeof params !== 'string' || !/^[0-9a-fA-F]+$/.test(params)) { - throw new Error('[Error] decode, params should be hex-string.'); - } - - const Byte_Len = typeObj.byteLength; - const _params = params.substring(0, Byte_Len * 2); - const Data_Len = _params.length / 2; - - if (Byte_Len !== Data_Len) { - throw lengthError(typeObj, Data_Len, 'Byte_Len !== Data_Len'); - } - - const Actual_Byte_Len = typeObj.actualByteLen; - const Offset = Byte_Len - Actual_Byte_Len; - if (Data_Len < Offset) { - throw lengthError(typeObj, Actual_Byte_Len, 'Data_Len < Offset'); - } - - return { - result: typeObj.type === 'bytes' ? _params.substring(0, _params.length - Offset * 2) : _params.substring(Offset * 2), - params: params.substring(Data_Len * 2), - _params - }; -} - - -export function decode(typeObj, params) { - const res = decodeToHexData(typeObj, params); - - return { - result: getRawData(typeObj, res.result, res._params), - params: res.params - }; -} - - -function getRawData({ type, typeStr, actualByteLen }, params, _params) { - switch (type) { - case 'address': - return getAddressFromOriginalAddress(params); - case 'bool': - return showNumber(params === '01' ? '1' : '0', 'uint'); - case 'number': - return showNumber(params, typeStr, actualByteLen, _params); - case 'gid': - return params; - case 'tokenId': - return showTokenId(params); - } -} - -function getBytesData({ type, typeStr, actualByteLen }, params) { - switch (type) { - case 'address': - return formatAddr(params); - case 'bool': - return formatNumber(params ? '1' : '0', 'uint'); - case 'number': - return formatNumber(params, typeStr, actualByteLen); - case 'gid': - return formatGid(params); - case 'tokenId': - return fomatTokenId(params); - } -} - -function formatAddr(address) { - const addr = getOriginalAddressFromAddress(address); - return Buffer.from(addr, 'hex'); -} - -function formatGid(gid) { - if (!gid || !/^[0-9a-fA-F]+$/.test(gid) || gid.length !== 20) { - throw new Error(`[Error] Illegal gid. ${ gid }`); - } - return Buffer.from(gid, 'hex'); -} - -function formatNumber(params, typeStr, actualByteLen?) { - const isSafe = isSafeInteger(params); - if (isSafe === -1) { - throw new Error(`${ integerIllegal.message }, number: ${ params }, type: ${ typeStr }`); - } else if (isSafe === 0) { - throw new Error(`${ unsafeInteger.message }, number: ${ params }, type: ${ typeStr }`); - } - - const num = new BigNumber(params); - const bitLen = num.bitLength(); - - if (bitLen > actualByteLen * 8) { - throw new Error(`[Error] Out of range: ${ params }, ${ typeStr }`); - } - - if (typeStr.indexOf('uint') === 0) { - if (num.cmp(new BigNumber(0)) < 0) { - throw new Error(`[Error] Uint shouldn't be a negative number ${ params }`); - } - return num.toArray(); - } - - return num.toTwos(256).toArray('be'); -} - -function fomatTokenId(tokenId) { - const originalTokenId = getOriginalTokenIdFromTokenId(tokenId); - if (!originalTokenId) { - throw new Error(`[Error] Illegal tokenId. ${ tokenId }`); - } - return Buffer.from(originalTokenId, 'hex'); -} - -function showNumber(str, typeStr, actualByteLen?, _params?) { - let num = new BigNumber(str, 16); - let actualNum = new BigNumber(_params, 16); - - if (typeStr.indexOf('int') === 0) { - num = num.fromTwos(actualByteLen ? actualByteLen * 8 : ''); - actualNum = actualNum.fromTwos(256); - } - - const bitLen = actualNum.bitLength(); - if (bitLen > actualByteLen * 8) { - throw new Error(`[Error] Out of range: ${ _params }, ${ typeStr }`); - } - - return num.toString(); -} - -function showTokenId(originalTokenId) { - const tokenId = getTokenIdFromOriginalTokenId(originalTokenId); - if (!tokenId) { - throw new Error(`[Error] Illegal tokenId. ${ originalTokenId }`); - } - return tokenId; -} - - -function lengthError(typeObj, length, type = '') { - return new Error(`[Error] Illegal length. ${ JSON.stringify(typeObj) }, data length: ${ length }, ${ type }`); -} diff --git a/src/abi/coder/dynamic.ts b/src/abi/coder/dynamic.ts deleted file mode 100644 index 50187ba2..00000000 --- a/src/abi/coder/dynamic.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { encode as commonEncode, encodeBytesData, decode as commonDecode, decodeToHexData } from './common'; - - -export function encode(typeObj, params) { - const Bytes_Data = getBytesData(typeObj.type, params); - - if (typeObj.byteLength) { - return encodeBytesData(typeObj, Bytes_Data); - } - - let result = dynamicEncode(Bytes_Data); - if (typeObj.type === 'bytes') { - const dataLength = 32 * Math.ceil(Bytes_Data.length / 32); - result = commonEncode({ type: 'number', typeStr: 'uint', byteLength: 32 }, dataLength).result + result; - } - - return { result, typeObj }; -} - -export function decode(typeObj, params) { - const Type = typeObj.type; - - if (typeObj.byteLength) { - const decodeRes = decodeToHexData(typeObj, params); - return { - result: getRawData(typeObj.type, decodeRes.result), - params: decodeRes.params - }; - } - - const _params = Type === 'bytes' ? params.substring(64) : params; - const res = dynamicDecode(_params); - - return { - result: getRawData(Type, res.result), - params: res.params - }; -} - - -function getRawData(type, params) { - if (type === 'string') { - return Buffer.from(params, 'hex').toString('utf8'); - } - return params; -} - -function getBytesData(type, params) { - if (typeof params !== 'string') { - throw new Error('[Error] Illegal params. Should be string'); - } - - if (type === 'string') { - return Buffer.from(params, 'utf8'); - } - - const is0xHex = /^0x[0-9a-fA-F]+$/.test(params) && params.length % 2 === 0; - const isHex = /^[0-9a-fA-F]+$/.test(params) && params.length % 2 === 0; - - if (type === 'bytes' && !is0xHex && !isHex) { - throw new Error('[Error] Illegal params. Should be hex-string.'); - } - - if (isHex) { - return Buffer.from(params, 'hex'); - } - return Buffer.from(params.substring(2), 'hex'); -} - -function dynamicEncode(bytesData) { - const Str_Len = bytesData.length; - const Data_Length = 32 * Math.ceil(Str_Len / 32); - - const bytesLen = commonEncode({ type: 'number', typeStr: 'uint', byteLength: 32 }, Str_Len).result; - - const len = bytesLen.length / 2 + Data_Length; - const arr = new Uint8Array(len); - - arr.set(Buffer.from(bytesLen, 'hex')); - arr.set(bytesData, bytesLen.length / 2); - return Buffer.from(arr).toString('hex'); -} - -function dynamicDecode(params) { - const Str_Len = commonDecode({ type: 'number', typeStr: 'uint', byteLength: 32 }, params.substring(0, 64)).result; - const Data_Length = 32 * Math.ceil(Str_Len / 32); - - return { - result: params.substring(64, 64 + Str_Len * 2), - params: params.substring(64 + Data_Length * 2) - }; -} diff --git a/src/abi/coder/gid.ts b/src/abi/coder/gid.ts new file mode 100644 index 00000000..64fdf702 --- /dev/null +++ b/src/abi/coder/gid.ts @@ -0,0 +1,24 @@ +import { Coder, Reader, Writer } from './index'; +import { leftPadZero } from '../utils'; + +export class GidCoder extends Coder { + constructor(localName: string) { + super('gid', 'gid', localName, false); + } + + defaultValue(): string { + return '00000000000000000001'; + } + + encode(writer: Writer, value: string): number { + if (!value || !/^[0-9a-fA-F]+$/.test(value) || value.length !== 20) { + throw new Error(`[Error] Illegal gid. ${ value }`); + } + return writer.writeValue(value); + } + + decode(reader: Reader): any { + return leftPadZero(reader.readValue().toString(16), 10); + } +} + diff --git a/src/abi/coder/index.ts b/src/abi/coder/index.ts index 383dc31b..72468abc 100644 --- a/src/abi/coder/index.ts +++ b/src/abi/coder/index.ts @@ -1,282 +1,309 @@ -import { isArray } from '~@vite/vitejs-utils'; -import { formatType } from '../inputsType'; - -import { encode as commonEncode, decode as commonDecode } from './common'; -import { encode as dynamicEncode, decode as dynamicDecode } from './dynamic'; - -const encode = { - address: commonEncode, - gid: commonEncode, - tokenId: commonEncode, - number: commonEncode, - bool: commonEncode, - string: dynamicEncode, - bytes: dynamicEncode -}; - -const decode = { - address: commonDecode, - gid: commonDecode, - tokenId: commonDecode, - number: commonDecode, - bool: commonDecode, - string: dynamicDecode, - bytes: dynamicDecode -}; - -export function encodeParameter(typeStr, params) { - const typeObj = formatType(typeStr); - if (!typeObj.isArr && [ 'string', 'boolean', 'number' ].indexOf(typeof params) === -1) { - throw new Error(`[Error] Illegal type or params. type: ${ typeObj.type }, params: ${ params }`); - } +import * as BigNumber from 'bn.js'; +import { arrayify, hexlify } from '../utils'; - if (typeObj.isArr && !isArray(params)) { - try { - params = JSON.parse(params); - if (!isArray(params)) { - throw new Error(`[Error] Illegal type or params. type: ${ typeObj.typeStr }, params: ${ params }`); - } - } catch (err) { - throw new Error(`[Error] Illegal type or params. type: ${ typeObj.typeStr }, params: ${ params }`); - } - } +export interface Result extends ReadonlyArray { + readonly [key: string]: any; +} - if (!typeObj.isArr) { - return encode[typeObj.type](typeObj, params); - } +export { BigNumber }; - return encodeArrs(typeObj, params); -} +export abstract class Coder { + // The coder name: + // - address, uint256, tuple, array, etc. + readonly name: string; -export function encodeParameters(types, params) { - if (typeof params === 'string') { - params = JSON.parse(params); - } + // The fully expanded type, including composite types: + // - address, uint256, tuple(address,bytes), uint256[3][4][], etc. + readonly type: string; - if (!isArray(types)) { - throw new Error('[Error] Illegal inputs. Inputs should be array.'); - } + // The localName bound in the signature, in this example it is "baz": + // - tuple(address foo, uint bar) baz + readonly localName: string; - // console.log(types); - if (!types.length) { - return ''; - } + // Whether this type is dynamic: + // - Dynamic: bytes, string, address[], tuple(boolean[]), etc. + // - Static: address, uint256, boolean[3], tuple(address, uint8) + readonly dynamic: boolean; - if (!isArray(params) || types.length !== params.length) { - throw new Error('[Error] Illegal params. Params should be array and the length should be equal to inputs.length'); + protected constructor(name: string, type: string, localName: string, dynamic: boolean) { + this.name = name; + this.type = type; + this.localName = localName; + this.dynamic = dynamic; } - const tempResult = []; - const dynamicRes = []; - let totalLength = 0; + pack(writer: Writer, coders: ReadonlyArray, values: Array | { [ name: string ]: any }): number { + let arrayValues: Array = null; - types.forEach((type, i) => { - const _res = encodeParameter(type, params[i]); + if (Array.isArray(values)) { + arrayValues = values; + } else if (values && typeof (values) === 'object') { + const unique: { [ name: string ]: boolean } = { }; - if (!_res.typeObj.isDynamic) { - totalLength += _res.result.length; - tempResult.push(_res.result); - return; - } + arrayValues = coders.map(coder => { + const name = coder.localName; + if (!name) { + throw new Error(`cannot encode object for signature with missing names: ${ coder }`); + } + + if (unique[name]) { + throw new Error(`cannot encode object for signature with duplicate names: ${ coder }`); + } + + unique[name] = true; - let result = _res.result; - if (_res.typeObj.type === 'bytes' && !_res.typeObj.isArr) { - result = result.slice(64); + return values[name]; + }); + } else { + throw new Error(`invalid tuple value: ${ values }`); } - totalLength += 64; - tempResult.push(false); - dynamicRes.push(result); - }); - - let result = ''; - let dynamicResult = ''; - tempResult.forEach(_r => { - if (_r) { - result += _r; - return; + if (coders.length !== arrayValues.length) { + throw new Error(`types/value length mismatch: ${ values }`); } - const index = (totalLength + dynamicResult.length) / 2; - result += encode.number({ type: 'number', typeStr: 'uint', byteLength: 32, isArr: false }, index).result; - dynamicResult += dynamicRes.shift(); - }); + const staticWriter = new Writer(writer.wordSize); + const dynamicWriter = new Writer(writer.wordSize); - return result + dynamicResult; -} + const updateFuncs: Array<(baseOffset: number) => void> = []; + coders.forEach((coder, index) => { + const value = arrayValues[index]; -export function decodeParameter(typeStr, params) { - const typeObj = formatType(typeStr); - if (!typeObj.isArr) { - return decode[typeObj.type](typeObj, params).result; - } - return decodeArrs(typeObj, params); -} + if (coder.dynamic) { + // Get current dynamic offset (for the future pointer) + const dynamicOffset = dynamicWriter.length; -export function decodeParameters(types, params) { - // console.log('startDecode', types, params); + // Encode the dynamic value into the dynamicWriter, including subarray + coder.encode(dynamicWriter, value); - if (!isArray(types)) { - throw new Error('[Error] Illegal types. Should be array.'); - } + // Prepare to populate the correct offset once we are done + const updateFunc = staticWriter.writeUpdatableValue(); + updateFuncs.push((baseOffset: number) => { + updateFunc(baseOffset + dynamicOffset); + }); + } else { + coder.encode(staticWriter, value); + } + }); + + // Backfill all the dynamic offsets, now that we know the static length + updateFuncs.forEach(func => { + func(staticWriter.length); + }); - if (!params) { - return null; + let length = writer.appendWriter(staticWriter); + length += writer.appendWriter(dynamicWriter); + return length; } - let _params = params; - const resArr = []; - const indexArr = []; - - types.forEach(type => { - const typeObj = formatType(type); - // console.log(typeObj); - if (!typeObj.isDynamic && typeObj.isArr) { - let len = 0; - typeObj.arrLen.forEach(_l => { - len += _l * typeObj.byteLength; - }); - const _p = _params.slice(0, len * 2); - _params = _params.slice(len * 2); - resArr.push({ - isDynamic: false, - result: decodeArrs(typeObj, _p) - }); - return; - } + unpack(reader: Reader, coders: Array): Result { + let values: any = []; - if (!typeObj.isDynamic) { - const _res = decode[typeObj.type](typeObj, _params); - _params = _res.params; - resArr.push({ - isDynamic: false, - result: _res.result - }); - return; - } + // A reader anchored to this base + const baseReader = reader.subReader(0); - const _res = decode.number({ type: 'number', typeStr: 'uint', byteLength: 32, isArr: false }, _params); - const index = _res.result; - _params = _res.params; - indexArr.push(index * 2); - resArr.push({ - isDynamic: true, - typeObj, - index: index * 2 + coders.forEach(coder => { + let value: any = null; + + if (coder.dynamic) { + const offset = reader.readValue(); + const offsetReader = baseReader.subReader(offset.toNumber()); + value = coder.decode(offsetReader); + } else { + value = coder.decode(reader); + } + + if (value !== undefined) { + values.push(value); + } }); - }); - - const result = []; - let currentInx = 0; - resArr.forEach((_res, i) => { - if (!_res.isDynamic) { - result.push(_res.result); - return; - } - let _p; - if ((currentInx + 1) === indexArr.length) { - _p = params.slice(_res.index); - } else { - _p = params.slice(_res.index, indexArr[currentInx + 1]); - } + // We only output named properties for uniquely named coders + const uniqueNames = coders.reduce((accum, coder) => { + const name = coder.localName; + if (name) { + if (!accum[name]) { + accum[name] = 0; + } + accum[name]++; + } + return accum; + }, { }); + + // Add any named parameters (i.e. tuples) + const tuple = { }; + coders.forEach((coder: Coder, index: number) => { + let name = coder.localName; + if (!name || uniqueNames[name] !== 1) { + return; + } + + if (name === 'length') { + name = '_length'; + } - if (_res.typeObj.type === 'bytes' && !_res.typeObj.isArr) { - const len = 32 * Math.ceil(_p.length / 2 / 32); - _p = encode.number({ type: 'number', typeStr: 'uint', byteLength: 32 }, len).result + _p; + if (values[name] != null) { + return; + } + + if (this.name === 'tuple' && this.localName !== '_') { + tuple[name] = values[index]; + } else { // TODO: enable to add name index to decode result + values[name] = values[index]; + } + }); + if (this.name === 'tuple' && this.localName !== '_' && Object.keys(tuple).length === values.length) { + values = tuple; } - currentInx++; - result.push(decodeParameter(types[i], _p)); - }); + return Object.freeze(values); + } + + abstract encode(writer: Writer, value: any): number; + abstract decode(reader: Reader): any; - return result; + abstract defaultValue(): any; } +export class Writer { + readonly wordSize: number; + + _data: Buffer[]; + _dataLength: number; + _padding: Buffer; -function encodeArr(typeObj, arrLen, params) { - if (!params || (arrLen && params.length !== Number(arrLen))) { - throw new Error(`[Error] Params.length !== arr.length. Params: ${ JSON.stringify(params) }. ${ JSON.stringify(typeObj) }`); + constructor(wordSize?: number) { + this.wordSize = wordSize || 32; + this._data = [ ]; + this._dataLength = 0; + this._padding = Buffer.alloc(this.wordSize); } - let result = ''; - params.forEach(_param => { - const res = encode[typeObj.type](typeObj, _param); - result += res.result; - }); + get data(): string { + let result = ''; + this._data.forEach(item => { + result += hexlify(item); + }); + return result; + } - const bytesArrLen = arrLen ? '' - : encode.number({ type: 'number', typeStr: 'uint', byteLength: 32, isArr: false }, params.length).result; + get length(): number { + return this._dataLength; + } - return bytesArrLen + result; -} + _writeData(data: Buffer): number { + this._data.push(data); + this._dataLength += data.length; + return data.length; + } -function encodeArrs(typeObj, params) { - let result = ''; - const lenArr = typeObj.arrLen; + appendWriter(writer: Writer): number { + // let result = ''; + // this._data.forEach(item => { + // result += Buffer.concat(item); + // }); + return this._writeData(Buffer.concat(writer._data)); + } - const loop = (params, i = 0) => { - if (i === lenArr.length - 1) { - result += encodeArr(typeObj, lenArr[lenArr.length - i - 1], params); - return; + // Arrayish items; padded on the right to wordSize + writeBytes(value: Buffer | string): number { + if (typeof (value) === 'string') { + value = Buffer.from(value, 'utf8'); } - i++; - isArray(params) && params.forEach(_p => { - loop(_p, i); - }); - }; - - loop(params); - return { typeObj, result }; -} + let bytes = arrayify(value); + const paddingOffset = bytes.length % this.wordSize; + if (paddingOffset) { + bytes = Buffer.concat([ bytes, this._padding.slice(paddingOffset) ]); + } + return this._writeData(bytes); + } -function decodeArr(typeObj, arrLen, params) { - let _param = params; - if (typeObj.isDynamic) { - const len = params.substring(0, 64); - arrLen = decode.number({ type: 'number', typeStr: 'uint', byteLength: 32, isArr: false }, len).result; - _param = params.substring(64); + _getValue(value: number | bigint | string | BigNumber): Buffer { + if (value instanceof BigNumber) { + value = value.toString(16); + } + let bytes = arrayify(value); + if (bytes.length > this.wordSize) { + throw new Error(`value out-of-bounds ${ this.wordSize } ${ bytes.length }`); + } + if (bytes.length % this.wordSize) { + bytes = Buffer.concat([ this._padding.slice(bytes.length % this.wordSize), bytes ]); + } + return bytes; } - const result = []; - for (let i = 0; i < arrLen; i++) { - const res = decode[typeObj.type](typeObj, _param); - result.push(res.result); - _param = res.params; + writeValue(value: number | bigint | string | BigNumber): number { + return this._writeData(this._getValue(value)); } - return { result, params: _param }; + writeUpdatableValue(): (value: number | bigint | string) => void { + const offset = this._data.length; + this._data.push(this._padding); + this._dataLength += this.wordSize; + return (value: number | bigint | string) => { + this._data[offset] = this._getValue(value); + }; + } } -function decodeArrs(typeObj, params) { - const lenArr = typeObj.arrLen; +export class Reader { + readonly wordSize: number; + readonly allowLoose: boolean; + readonly _data: Buffer; - const loop = (i = 0, result?) => { - if ((lenArr.length <= 1 && i === lenArr.length) - || (lenArr.length > 1 && i === lenArr.length - 1)) { - return result; - } + _offset: number; - const l = lenArr[i]; - let _r = []; + constructor(data: Buffer | string, wordSize?: number, allowLoose?: boolean) { + this._data = arrayify(data); + this.wordSize = wordSize || 32; + this.allowLoose = allowLoose; + this._offset = 0; + } - if (result) { - let resultOpt = result && result.length; - while (resultOpt) { - _r.push(result.splice(0, l)); - resultOpt = result && result.length; - } - } else { - while (params) { - const _res = decodeArr(typeObj, l, params); - params = _res.params; - _r.push(_res.result); + get data(): string { + return hexlify(this._data); + } + + get consumed(): number { + return this._offset; + } + + coerce(coder: Coder, value: any): any { + if (coder.name.match('^u?int([0-9]+)$')) { + // TODO: enable to return numeric types for numbers + // if (parseInt(match[1]) <= 48 || value.lt(new BigNumber(Number.MAX_SAFE_INTEGER))) { + // value = value.toNumber(); + // } else { + // value = value.toString(); + // } + value = value.toString(); + } + return value; + } + + _peekBytes(offset: number, length: number, loose?: boolean): Buffer { + let alignedLength = Math.ceil(length / this.wordSize) * this.wordSize; + if (this._offset + alignedLength > this._data.length) { + if (this.allowLoose && loose && this._offset + length <= this._data.length) { + alignedLength = length; + } else { + throw new Error(`data out-of-bounds ${ this._data.length } ${ this._offset + alignedLength }`); } - _r = _r.length > 1 ? _r : _r[0]; } + return this._data.slice(this._offset, this._offset + alignedLength); + } - i++; - return loop(i, _r); - }; - return loop(); + subReader(offset: number): Reader { + return new Reader(this._data.slice(this._offset + offset), this.wordSize, this.allowLoose); + } + + readBytes(length: number, loose?: boolean): Buffer { + const bytes = this._peekBytes(0, length, !!loose); + this._offset += bytes.length; + return bytes.slice(0, length); + } + + readValue(): BigNumber { + return new BigNumber(this.readBytes(this.wordSize)); + } } diff --git a/src/abi/coder/null.ts b/src/abi/coder/null.ts new file mode 100644 index 00000000..0398924c --- /dev/null +++ b/src/abi/coder/null.ts @@ -0,0 +1,23 @@ +import { Coder, Reader, Writer } from './index'; + +export class NullCoder extends Coder { + constructor(localName: string) { + super('null', '', localName, false); + } + + defaultValue(): null { + return null; + } + + encode(writer: Writer, value: any): number { + if (value != null) { + throw new Error(`value not null: ${ value }`); + } + return writer.writeBytes(Buffer.from([ ])); + } + + decode(reader: Reader): any { + reader.readBytes(0); + return reader.coerce(this, null); + } +} diff --git a/src/abi/coder/number.ts b/src/abi/coder/number.ts new file mode 100644 index 00000000..4c358dd1 --- /dev/null +++ b/src/abi/coder/number.ts @@ -0,0 +1,56 @@ +import { Coder, Reader, Writer, BigNumber } from './index'; + +const MaxUint256 = new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 'hex'); + +export class NumberCoder extends Coder { + readonly size: number; + readonly signed: boolean; + + constructor(size: number, signed: boolean, localName: string) { + const name = ((signed ? 'int' : 'uint') + (size * 8)); + super(name, name, localName, false); + + this.size = size; + this.signed = signed; + } + + defaultValue(): number { + return 0; + } + + encode(writer: Writer, value: bigint | number | string | BigNumber): number { + if (typeof (value) === 'bigint') { + value = value.toString(16); + } + let v = new BigNumber(value); + // Check bounds are safe for encoding + const maxUintValue = MaxUint256.clone().imaskn(writer.wordSize * 8); + if (this.signed) { + const bounds = maxUintValue.imaskn(this.size * 8 - 1); + if (v.gt(bounds) || v.lt(bounds.add(new BigNumber(1)).mul(new BigNumber(-1)))) { + throw new Error(`value out-of-bounds: ${ value }`); + } + } else if (v.lt(new BigNumber(0)) || v.gt(maxUintValue.imaskn(this.size * 8))) { + throw new Error(`value out-of-bounds: ${ value }`); + } + + v = v.toTwos(this.size * 8).imaskn(this.size * 8); + + if (this.signed) { + v = v.fromTwos(this.size * 8).toTwos(8 * writer.wordSize); + } + + return writer.writeValue(v); + } + + decode(reader: Reader): any { + let value = reader.readValue().imaskn(this.size * 8); + + if (this.signed) { + value = value.fromTwos(this.size * 8); + } + + return reader.coerce(this, value); + } +} + diff --git a/src/abi/coder/string.ts b/src/abi/coder/string.ts new file mode 100644 index 00000000..829f8883 --- /dev/null +++ b/src/abi/coder/string.ts @@ -0,0 +1,20 @@ +import { Reader, Writer } from './index'; +import { DynamicBytesCoder } from './bytes'; + +export class StringCoder extends DynamicBytesCoder { + constructor(localName: string) { + super('string', localName); + } + + defaultValue(): string { + return ''; + } + + encode(writer: Writer, value: any): number { + return super.encode(writer, Buffer.from(value, 'utf8')); + } + + decode(reader: Reader): any { + return Buffer.from(super.decode(reader)).toString('utf8'); + } +} diff --git a/src/abi/coder/tokenId.ts b/src/abi/coder/tokenId.ts new file mode 100644 index 00000000..55992776 --- /dev/null +++ b/src/abi/coder/tokenId.ts @@ -0,0 +1,23 @@ +import { Coder, Reader, Writer } from './index'; +import { getOriginalTokenIdFromTokenId, getTokenIdFromOriginalTokenId} from '~@vite/vitejs-utils'; +import { leftPadZero } from '../utils'; + +export class TokenIdCoder extends Coder { + constructor(localName: string) { + super('tokenId', 'tokenId', localName, false); + } + + defaultValue(): string { + return getTokenIdFromOriginalTokenId('00000000000000000000'); + } + + encode(writer: Writer, value: string): number { + value = getOriginalTokenIdFromTokenId(value); + return writer.writeValue(value); + } + + decode(reader: Reader): any { + return getTokenIdFromOriginalTokenId(leftPadZero(reader.readValue().toString(16), 10)); + } +} + diff --git a/src/abi/coder/tuple.ts b/src/abi/coder/tuple.ts new file mode 100644 index 00000000..0d0295b8 --- /dev/null +++ b/src/abi/coder/tuple.ts @@ -0,0 +1,76 @@ +import { Coder, Reader, Writer } from './index'; + +export class TupleCoder extends Coder { + readonly coders: Array; + + constructor(coders: Array, localName: string) { + let dynamic = false; + const types: Array = []; + coders.forEach(coder => { + if (coder.dynamic) { + dynamic = true; + } + types.push(coder.type); + }); + const type = (`tuple(${ types.join(',') })`); + + super('tuple', type, localName, dynamic); + this.coders = coders; + } + + defaultValue(): any { + let values: any = [ ]; + this.coders.forEach(coder => { + values.push(coder.defaultValue()); + }); + + // We only output named properties for uniquely named coders + const uniqueNames = this.coders.reduce((accum, coder) => { + const name = coder.localName; + if (name) { + if (!accum[name]) { + accum[name] = 0; + } + accum[name]++; + } + return accum; + }, { }); + + // Add named values + const tuple = {}; + this.coders.forEach((coder: Coder, index: number) => { + let name = coder.localName; + if (!name || uniqueNames[name] !== 1) { + return; + } + + if (name === 'length') { + name = '_length'; + } + + if (values[name] != null) { + return; + } + + if (this.localName !== '_') { + tuple[name] = values[index]; + } + // values[name] = values[index]; + }); + + if (Object.keys(tuple).length === values.length) { + values = tuple; + } + + return Object.freeze(values); + } + + encode(writer: Writer, value: Array | { [ name: string ]: any }): number { + return this.pack(writer, this.coders, value); + } + + decode(reader: Reader): any { + return reader.coerce(this, this.unpack(reader, this.coders)); + } +} + diff --git a/src/abi/encodeFunction.ts b/src/abi/encodeFunction.ts deleted file mode 100644 index edf991e7..00000000 --- a/src/abi/encodeFunction.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { blake2bHex, isArray, isObject } from '~@vite/vitejs-utils'; -import { getTypes } from './inputsType'; - - -export function encodeFunction(jsonFunction, methodName?) { - const isArr = isArray(jsonFunction); - const _jsonFunction = isArr ? getFunction(jsonFunction, methodName) : jsonFunction; - const result = jsonFunctionToString(_jsonFunction); - return blake2bHex(result, null, 32); -} - -export function getFunction(jsonFunction, methodName?) { - if (!isArray(jsonFunction) && isObject(jsonFunction)) { - return jsonFunction; - } - - if (jsonFunction.length !== 1 && !methodName) { - throw new Error('[Error] Param(s) missing, methodName.'); - } - - if (!methodName && jsonFunction.length === 1) { - return jsonFunction[0]; - } - - return jsonFunction.find(e => e.name === methodName); -} - - -function jsonFunctionToString(jsonFunction) { - const isObj = isObject(jsonFunction); - const isRightStr = /\w+\((\w\,\w)*|(\w*)\)/g; - - if (!isObj && !isRightStr.test(jsonFunction)) { - throw new Error(`[Error] Illegal jsonFunction. ${ JSON.stringify(jsonFunction) }`); - } - - if (isRightStr.test(jsonFunction)) { - return jsonFunction; - } - - if (jsonFunction.name && isRightStr.test(jsonFunction.name)) { - return jsonFunction.name; - } - - const types = getTypes(jsonFunction); - return `${ jsonFunction.name }(${ types.join(',') })`; -} diff --git a/src/abi/fragments.ts b/src/abi/fragments.ts new file mode 100644 index 00000000..663859d1 --- /dev/null +++ b/src/abi/fragments.ts @@ -0,0 +1,1231 @@ +import { safeParseJson } from './utils'; + +export interface JsonParamType { + readonly name?: string; + readonly indexed?: boolean; + readonly type?: string; + readonly internalType?: any; + readonly components?: Array; +} + +export interface JsonFragment { + readonly name?: string; + readonly type?: string; + + readonly anonymous?: boolean; + + readonly payable?: boolean; + readonly constant?: boolean; + readonly stateMutability?: string; + + readonly inputs?: Array; + readonly outputs?: Array; +} + +// AST Node parser state +type ParseState = { + allowArray?: boolean, + allowName?: boolean, + allowParams?: boolean, + allowType?: boolean, + readArray?: boolean, +}; + +// AST Node +type ParseNode = { + parent?: any, + type?: string, + name?: string, + state?: ParseState, + indexed?: boolean, + components?: Array +}; + +const ModifiersBytes: { [name: string]: boolean } = {calldata: true, memory: true, storage: true}; +const ModifiersNest: { [name: string]: boolean } = {calldata: true, memory: true}; + +function checkModifier(type: string, name: string): boolean { + if (type === 'bytes' || type === 'string') { + if (ModifiersBytes[name]) { + return true; + } + } else if (type === 'address') { + if (name === 'payable') { + return true; + } + } else if (type.indexOf('[') >= 0 || type === 'tuple') { + if (ModifiersNest[name]) { + return true; + } + } + if (ModifiersBytes[name] || name === 'payable') { + throw new Error(`invalid modifier ${ name }`); + } + return false; +} + +function parseParamType(param: string, allowIndexed: boolean): ParseNode { + const originalParam = param; + + function throwError(i: number) { + throw new Error(`unexpected character at position ${ i } of ${ param }`); + } + + param = param.replace(/\s/g, ' '); + + function newNode(parent: ParseNode): ParseNode { + const node: ParseNode = {type: '', name: '', parent: parent, state: {allowType: true}}; + if (allowIndexed) { + node.indexed = false; + } + return node; + } + + const parent: ParseNode = {type: '', name: '', state: {allowType: true}}; + let node = parent; + + for (let i = 0; i < param.length; i++) { + const c = param[i]; + switch (c) { + case '(': + if (node.state.allowType && node.type === '') { + node.type = 'tuple'; + } else if (!node.state.allowParams) { + throwError(i); + } + node.state.allowType = false; + node.type = verifyType(node.type); + node.components = [newNode(node)]; + node = node.components[0]; + break; + + case ')': { + delete node.state; + + if (node.name === 'indexed') { + if (!allowIndexed) { + throwError(i); + } + node.indexed = true; + node.name = ''; + } + + if (checkModifier(node.type, node.name)) { + node.name = ''; + } + + node.type = verifyType(node.type); + + const child = node; + node = node.parent; + if (!node) { + throwError(i); + } + delete child.parent; + node.state.allowParams = false; + node.state.allowName = true; + node.state.allowArray = true; + break; + } + case ',': + delete node.state; + + if (node.name === 'indexed') { + if (!allowIndexed) { + throwError(i); + } + node.indexed = true; + node.name = ''; + } + + if (checkModifier(node.type, node.name)) { + node.name = ''; + } + + node.type = verifyType(node.type); + + // eslint-disable-next-line no-case-declarations + const sibling: ParseNode = newNode(node.parent); + // { type: "", name: "", parent: node.parent, state: { allowType: true } }; + node.parent.components.push(sibling); + delete node.parent; + node = sibling; + break; + + // Hit a space... + case ' ': + // If reading type, the type is done and may read a param or name + if (node.state.allowType) { + if (node.type !== '') { + node.type = verifyType(node.type); + delete node.state.allowType; + node.state.allowName = true; + node.state.allowParams = true; + } + } + + // If reading name, the name is done + if (node.state.allowName) { + if (node.name !== '') { + if (node.name === 'indexed') { + // eslint-disable-next-line max-depth + if (!allowIndexed) { + throwError(i); + } + // eslint-disable-next-line max-depth + if (node.indexed) { + throwError(i); + } + node.indexed = true; + node.name = ''; + } else if (checkModifier(node.type, node.name)) { + node.name = ''; + } else { + node.state.allowName = false; + } + } + } + + break; + + case '[': + if (!node.state.allowArray) { + throwError(i); + } + + node.type += c; + + node.state.allowArray = false; + node.state.allowName = false; + node.state.readArray = true; + break; + + case ']': + if (!node.state.readArray) { + throwError(i); + } + + node.type += c; + + node.state.readArray = false; + node.state.allowArray = true; + node.state.allowName = true; + break; + + default: + if (node.state.allowType) { + node.type += c; + node.state.allowParams = true; + node.state.allowArray = true; + } else if (node.state.allowName) { + node.name += c; + delete node.state.allowArray; + } else if (node.state.readArray) { + node.type += c; + } else { + throwError(i); + } + } + } + + if (node.parent) { + throw new Error(`unexpected eof param ${ param }`); + } + + delete parent.state; + + if (node.name === 'indexed') { + if (!allowIndexed) { + throwError(originalParam.length - 7); + } + if (node.indexed) { + throwError(originalParam.length - 7); + } + node.indexed = true; + node.name = ''; + } else if (checkModifier(node.type, node.name)) { + node.name = ''; + } + + parent.type = verifyType(parent.type); + + return parent; +} + +function populate(object: any, params: any) { + for (const key in params) { + Object.defineProperty(object, key, { + enumerable: true, + value: params[key], + writable: false + }); + } +} + +export enum FormatTypes { + Sighash = 'sighash', // Bare formatting, as is needed for computing a sighash of an event or function + Minimal = 'minimal', // Human-Readable with Minimal spacing and without names (compact human-readable) + Full = 'full', // Human-Readable with nice spacing, including all names + Json = 'json' // JSON-format +} + +const paramTypeArray = new RegExp(/^(.*)\[([0-9]*)\]$/); + +export class ParamType { + static from(value: string | JsonParamType | ParamType, allowIndexed?: boolean): ParamType { + if (typeof (value) === 'string') { + const jsonParam: JsonParamType = safeParseJson(value); + if (jsonParam) { + value = jsonParam; + } else { + return ParamType.fromString(value, allowIndexed); + } + } + return ParamType.fromObject(value); + } + + static fromObject(value: JsonParamType | ParamType): ParamType { + if (ParamType.isParamType(value)) { + return value; + } + + return new ParamType({ + name: (value.name || null), + type: verifyType(value.type), + indexed: ((value.indexed == null) ? null : !!value.indexed), + components: (value.components ? value.components.map(ParamType.fromObject) : null) + }); + } + + static fromString(value: string, allowIndexed?: boolean): ParamType { + function ParamTypify(node: ParseNode): ParamType { + return ParamType.fromObject({ + name: node.name, + type: node.type, + indexed: node.indexed, + components: node.components + }); + } + return ParamTypify(parseParamType(value, !!allowIndexed)); + } + + static isParamType(value: any): value is ParamType { + return !!(value != null && value._isParamType); + } + + // The local name of the parameter (of null if unbound) + readonly name: string; + + // The fully qualified type (e.g. "address", "tuple(address)", "uint256[3][]" + readonly type: string; + + // The base type (e.g. "address", "tuple", "array") + readonly baseType: string; + + // Indexable Paramters ONLY (otherwise null) + readonly indexed: boolean; + + // Tuples ONLY: (otherwise null) + // - sub-components + readonly components: Array; + + // Arrays ONLY: (otherwise null) + // - length of the array (-1 for dynamic length) + // - child type + readonly arrayLength: number; + readonly arrayChildren: ParamType; + readonly arrayDimension: number; + + readonly _isParamType: boolean; + + constructor(params: any) { + populate(this, params); + + const match = this.type.match(paramTypeArray); + if (match) { + populate(this, { + arrayLength: parseInt(match[2] || '-1'), + arrayChildren: ParamType.fromObject({ + type: match[1], + components: this.components + }), + arrayDimension: this.type.match(/\[([0-9]*)\]/g).length, + baseType: 'array' + }); + } else { + populate(this, { + arrayLength: null, + arrayChildren: null, + arrayDimension: null, + baseType: ((this.components == null) ? this.type : 'tuple') + }); + } + + this._isParamType = true; + + Object.freeze(this); + } + + // Format the parameter fragment + // - sighash: "(uint256,address)" + // - minimal: "tuple(uint256,address) indexed" + // - full: "tuple(uint256 foo, address bar) indexed baz" + format(format?: FormatTypes): string { + if (!format) { + format = FormatTypes.Sighash; + } + + if (format === FormatTypes.Json) { + const result: any = { + type: ((this.baseType === 'tuple') ? 'tuple' : this.type), + name: (this.name || undefined) + }; + if (typeof (this.indexed) === 'boolean') { + result.indexed = this.indexed; + } + if (this.components) { + result.components = this.components.map(comp => JSON.parse(comp.format(format))); + } + return JSON.stringify(result); + } + + let result = ''; + + // Array + if (this.baseType === 'array') { + result += this.arrayChildren.format(format); + result += `[${ this.arrayLength < 0 ? '' : String(this.arrayLength) }]`; + } else if (this.baseType === 'tuple') { + if (format !== FormatTypes.Sighash) { + result += this.type; + } + result += `(${ this.components.map(comp => comp.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') })`; + } else { + result += this.type; + } + + if (format !== FormatTypes.Sighash) { + if (this.indexed === true) { + result += ' indexed'; + } + if (format === FormatTypes.Full && this.name) { + result += ` ${ this.name }`; + } + } + + return result; + } +} + +function parseParams(value: string, allowIndex: boolean): Array { + return splitNesting(value).map(param => ParamType.fromString(param, allowIndex)); +} + +type TypeCheck = { -readonly [K in keyof T]: T[K] }; + +interface _Fragment { + readonly type: string; + readonly name: string; + readonly inputs: ReadonlyArray; +} + +export enum FragmentType { + Function = 'function', + Event = 'event', + Constructor = 'constructor', + Offchain = 'offchain', + Callback = 'callback', + Variable = 'variable', + Fallback = 'fallback', + Receive = 'receive' +} + +export abstract class Fragment implements _Fragment { + /** + * Parse fragment from existing Fragment instance, json object, json string or Solidity signatures + * @param value + */ + static from(value: Fragment | JsonFragment | string): Fragment { + if (Fragment.isFragment(value)) { + return value; + } + + if (typeof (value) === 'string') { + const jsonFragment: JsonFragment = safeParseJson(value); + if (jsonFragment) { + value = jsonFragment; + } else { + return Fragment.fromString(value); // parse signature + } + } + + return Fragment.fromObject(value); + } + + /** + * Parse fragment from existing Fragment instance or json + * @param value + */ + static fromObject(value: Fragment | JsonFragment): Fragment { + if (Fragment.isFragment(value)) { + return value; + } + + switch (value.type) { + case FragmentType.Function: + case FragmentType.Callback: + return FunctionFragment.fromObject(value); + case FragmentType.Event: + return EventFragment.fromObject(value); + case FragmentType.Constructor: + return ConstructorFragment.fromObject(value); + case FragmentType.Offchain: + return OffchainFragment.fromObject(value); + case FragmentType.Variable: + case FragmentType.Fallback: + case FragmentType.Receive: + return DefaultFragment.fromObject(value); + } + + throw new Error(`invalid fragment object ${ value }`); + } + + /** + * Parse fragment from Solidity ABI string + * @param value + */ + static fromString(value: string): Fragment { + // Make sure the "returns" is surrounded by a space and all whitespace is exactly one space + value = value.replace(/\s/g, ' '); + value = value.replace(/\(/g, ' (').replace(/\)/g, ') ').replace(/\s+/g, ' '); + value = value.trim(); + + if (value.split(' ')[0] === FragmentType.Event) { + return EventFragment.fromString(value.substring(5).trim()); + } else if (value.split(' ')[0] === FragmentType.Function + || value.split(' ')[0] === FragmentType.Callback) { + return FunctionFragment.fromString(value.substring(8).trim(), value.split(' ')[0]); + } else if (value.split('(')[0].trim() === FragmentType.Constructor) { + return ConstructorFragment.fromString(value.trim()); + } else if (value.split(' ')[0] === FragmentType.Offchain) { + return OffchainFragment.fromString(value.substring(8).trim()); + } else if (value.split(' ')[0] === 'getter') { + return OffchainFragment.fromString(value.substring(6).trim()); + } else if (value.split('(')[0].trim() === FragmentType.Receive + || value.split('(')[0].trim() === FragmentType.Fallback + || value.split(' ')[0] === FragmentType.Variable) { + return DefaultFragment.fromString(value.trim()); + } + + throw new Error(`unsupported fragment ${ value }`); + } + + static isFragment(value: any): value is Fragment { + return !!(value && value._isFragment); + } + + readonly type: string; + readonly name: string; + readonly inputs: Array; + + readonly _isFragment: boolean; + + constructor(params: any) { + populate(this, params); + + this._isFragment = true; + + Object.freeze(this); + } + + abstract format(format?: FormatTypes): string; +} + +interface _EventFragment extends _Fragment { + readonly anonymous: boolean; +} + +export class EventFragment extends Fragment implements _EventFragment { + static from(value: EventFragment | JsonFragment | string): EventFragment { + if (typeof (value) === 'string') { + return EventFragment.fromString(value); + } + return EventFragment.fromObject(value); + } + + static fromObject(value: JsonFragment | EventFragment): EventFragment { + if (EventFragment.isEventFragment(value)) { + return value; + } + + if (value.type !== FragmentType.Event) { + throw new Error(`invalid event object ${ value }`); + } + + const params: TypeCheck<_EventFragment> = { + name: verifyIdentifier(value.name), + anonymous: value.anonymous, + inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), + type: FragmentType.Event + }; + if (params.inputs.filter(item => item.indexed).length > 3) { + throw new Error(`only up to 3 params can be indexed: ${ params.name }`); + } + + return new EventFragment(params); + } + + static fromString(value: string): EventFragment { + const match = value.match(regexParen); + if (!match) { + throw new Error(`invalid event string ${ value }`); + } + + let anonymous = false; + match[3].split(' ').forEach(modifier => { + switch (modifier.trim()) { + case 'anonymous': + anonymous = true; + break; + case '': + break; + default: + console.warn(`unknown modifier: ${ modifier }`); + } + }); + + return EventFragment.fromObject({ + name: match[1].trim(), + anonymous: anonymous, + inputs: parseParams(match[2], true), + type: FragmentType.Event + }); + } + + static isEventFragment(value: any): value is EventFragment { + return (value && value._isFragment && value.type === FragmentType.Event); + } + + readonly anonymous: boolean; + + format(format?: FormatTypes): string { + if (!format) { + format = FormatTypes.Sighash; + } + + if (format === FormatTypes.Json) { + return JSON.stringify({ + type: FragmentType.Event, + anonymous: this.anonymous, + name: this.name, + inputs: this.inputs.map(input => JSON.parse(input.format(format))) + }); + } + + let result = ''; + + if (format !== FormatTypes.Sighash) { + result += 'event '; + } + + result += `${ this.name }(${ this.inputs.map(input => input.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') }) `; + + if (format !== FormatTypes.Sighash) { + if (this.anonymous) { + result += 'anonymous '; + } + } + + return result.trim(); + } +} + +function parseModifiers(value: string, params: any): void { + params.constant = false; + params.payable = false; + params.stateMutability = 'nonpayable'; + + value.split(' ').forEach(modifier => { + switch (modifier.trim()) { + case 'constant': + params.constant = true; + break; + case 'payable': + params.payable = true; + params.stateMutability = 'payable'; + break; + case 'nonpayable': + params.payable = false; + params.stateMutability = 'nonpayable'; + break; + case 'pure': + params.constant = true; + params.stateMutability = 'pure'; + break; + case 'view': + params.constant = true; + params.stateMutability = 'view'; + break; + case 'external': + case 'public': + case '': + break; + default: + console.log(`unknown modifier: ${ modifier }`); + } + }); +} + +type StateInputValue = { + constant?: boolean; + payable?: boolean; + stateMutability?: string; + type?: string; +}; + +type StateOutputValue = { + constant: boolean; + payable: boolean; + stateMutability: string; +}; + +function verifyState(value: StateInputValue): StateOutputValue { + const result: any = { + constant: false, + payable: false, + stateMutability: 'nonpayable' + }; + if (value.type === FragmentType.Offchain) { + result.constant = true; + result.stateMutability = 'view'; + } else if (value.stateMutability != null) { + result.stateMutability = value.stateMutability; + + // Set (and check things are consistent) the constant property + result.constant = (result.stateMutability === 'view' || result.stateMutability === 'pure'); + if (value.constant != null) { + if ((!!value.constant) !== result.constant) { + throw new Error(`cannot have constant function with mutability ${ result.stateMutability } ${ value }`); + } + } + + // Set (and check things are consistent) the payable property + result.payable = (result.stateMutability === 'payable'); + if (value.payable != null) { + if ((!!value.payable) !== result.payable) { + throw new Error(`cannot have payable function with mutability ${ result.stateMutability } ${ value }`); + } + } + } else if (value.payable != null) { + result.payable = !!value.payable; + + // If payable we can assume non-constant; otherwise we can't assume + // if (value.constant == null && !result.payable && value.type !== 'constructor') { + // throw new Error(`unable to determine stateMutability ${ value }`); + // } + + result.constant = !!value.constant; + + if (result.constant) { + result.stateMutability = 'view'; + } else { + result.stateMutability = (result.payable ? 'payable' : 'nonpayable'); + } + + if (result.payable && result.constant) { + throw new Error(`cannot have constant payable function ${ value }`); + } + } else if (value.constant != null) { + result.constant = !!value.constant; + result.payable = !result.constant; + result.stateMutability = (result.constant ? 'view' : 'payable'); + } + + return result; +} + +interface _ConstructorFragment extends _Fragment { + stateMutability: string; + payable: boolean; +} + +export class ConstructorFragment extends Fragment implements _ConstructorFragment { + static from(value: ConstructorFragment | JsonFragment | string): ConstructorFragment { + if (typeof (value) === 'string') { + return ConstructorFragment.fromString(value); + } + return ConstructorFragment.fromObject(value); + } + + static fromObject(value: ConstructorFragment | JsonFragment): ConstructorFragment { + if (ConstructorFragment.isConstructorFragment(value)) { + return value; + } + + if (value.type !== FragmentType.Constructor) { + throw new Error(`invalid constructor object ${ value }`); + } + + const state = verifyState(value); + if (state.constant) { + throw new Error(`constructor cannot be constant ${ value }`); + } + + const params: TypeCheck<_ConstructorFragment> = { + name: null, + type: value.type, + inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), + payable: state.payable, + stateMutability: state.stateMutability + }; + + return new ConstructorFragment(params); + } + + static fromString(value: string): ConstructorFragment { + const params: any = {type: FragmentType.Constructor}; + + const parens = value.match(regexParen); + if (!parens || parens[1].trim() !== 'constructor') { + throw new Error(`invalid constructor string ${ value }`); + } + + params.inputs = parseParams(parens[2].trim(), false); + + parseModifiers(parens[3].trim(), params); + + return ConstructorFragment.fromObject(params); + } + + static isConstructorFragment(value: any): value is ConstructorFragment { + return (value && value._isFragment && value.type === FragmentType.Constructor); + } + + stateMutability: string; + payable: boolean; + + format(format?: FormatTypes): string { + if (!format) { + format = FormatTypes.Sighash; + } + + if (format === FormatTypes.Json) { + return JSON.stringify({ + type: FragmentType.Constructor, + stateMutability: ((this.stateMutability === 'nonpayable') ? undefined : this.stateMutability), + payable: this.payable, + inputs: this.inputs.map(input => JSON.parse(input.format(format))) + }); + } + + if (format === FormatTypes.Sighash) { + throw new Error('cannot format a constructor for sighash'); + } + + let result = `constructor(${ this.inputs.map(input => input.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') }) `; + + if (this.stateMutability && this.stateMutability !== 'nonpayable') { + result += `${ this.stateMutability } `; + } + + return result.trim(); + } +} + +export type FunctionLike = FunctionFragment | OffchainFragment; + +interface _FunctionFragment extends _Fragment { + stateMutability: string; + payable: boolean; + constant: boolean; + outputs?: Array; +} + +export class FunctionFragment extends Fragment implements _FunctionFragment { + static from(value: FunctionFragment | JsonFragment | string): FunctionFragment { + if (typeof (value) === 'string') { + return FunctionFragment.fromString(value); + } + return FunctionFragment.fromObject(value); + } + + static fromObject(value: FunctionFragment | JsonFragment): FunctionFragment { + if (FunctionFragment.isFunctionFragment(value)) { + return value; + } + + if (value.type !== FragmentType.Function && value.type !== FragmentType.Callback) { + throw new Error(`invalid function object ${ value }`); + } + + const state = verifyState(value); + + const params: TypeCheck<_FunctionFragment> = { + type: value.type, + name: verifyIdentifier(value.type === FragmentType.Callback ? `${ value.name }Callback` : value.name), + constant: state.constant, + inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), + outputs: (value.outputs ? value.outputs.map(ParamType.fromObject) : []), + payable: state.payable, + stateMutability: state.stateMutability + }; + + return new FunctionFragment(params); + } + + static fromString(value: string, type?: string): FunctionFragment { + if (!type) { + type = FragmentType.Function; + } + const params: any = {type: type}; + + const comps = value.split(' returns '); + if (comps.length > 2) { + throw new Error(`invalid function string ${ value }`); + } + + const parens = comps[0].match(regexParen); + if (!parens) { + throw new Error(`invalid function signature ${ value }`); + } + + params.name = parens[1].trim(); + if (params.name) { + verifyIdentifier(params.name); + } + + params.inputs = parseParams(parens[2], false); + + parseModifiers(parens[3].trim(), params); + + // We have outputs + if (comps.length > 1) { + const returns = comps[1].match(regexParen); + if (returns[1].trim() !== '' || returns[3].trim() !== '') { + throw new Error(`unexpected tokens ${ value }`); + } + params.outputs = parseParams(returns[2], false); + } else { + params.outputs = []; + } + + return FunctionFragment.fromObject(params); + } + + static isFunctionFragment(value: any): value is FunctionFragment { + return (value && value._isFragment && (value.type === FragmentType.Function || value.type === FragmentType.Callback)); + } + + stateMutability: string; + payable: boolean; + constant: boolean; + outputs?: Array; + + format(format?: FormatTypes): string { + if (!format) { + format = FormatTypes.Sighash; + } + + let _name = this.name; + if (format !== FormatTypes.Sighash && this.type === FragmentType.Callback) { + _name = this.name.replace(/Callback$/, ''); + } + + if (format === FormatTypes.Json) { + return JSON.stringify({ + type: this.type, + name: _name, + constant: this.constant, + stateMutability: ((this.stateMutability === 'nonpayable') ? undefined : this.stateMutability), + payable: this.payable, + inputs: this.inputs.map(input => JSON.parse(input.format(format))), + outputs: this.outputs.map(output => JSON.parse(output.format(format))) + }); + } + + let result = ''; + + if (format !== FormatTypes.Sighash) { + result += `${ this.type } `; + } + + result += `${ _name }(${ this.inputs.map(input => input.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') }) `; + + if (format !== FormatTypes.Sighash) { + if (this.stateMutability) { + if (this.stateMutability !== 'nonpayable') { + result += (`${ this.stateMutability } `); + } + } else if (this.constant) { + result += 'view '; + } + + if (this.outputs && this.outputs.length) { + result += `returns (${ this.outputs.map(output => output.format(format)).join(', ') }) `; + } + } + + return result.trim(); + } +} + +interface _OffchainFragment extends _Fragment { + outputs?: Array; +} + +export class OffchainFragment extends Fragment implements _OffchainFragment { + static from(value: OffchainFragment | JsonFragment | string): OffchainFragment { + if (typeof (value) === 'string') { + return OffchainFragment.fromString(value); + } + return OffchainFragment.fromObject(value); + } + + static fromObject(value: OffchainFragment | JsonFragment): OffchainFragment { + if (OffchainFragment.isOffchainFragment(value)) { + return value; + } + + if (value.type !== FragmentType.Offchain) { + throw new Error(`invalid offchain object ${ value }`); + } + + const params: TypeCheck<_OffchainFragment> = { + type: value.type, + name: verifyIdentifier(value.name), + inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), + outputs: (value.outputs ? value.outputs.map(ParamType.fromObject) : []) + }; + + return new OffchainFragment(params); + } + + static fromString(value: string): OffchainFragment { + const functionParams: FunctionFragment = FunctionFragment.fromString(value); + const params: TypeCheck<_OffchainFragment> = { + type: FragmentType.Offchain, + name: functionParams.name, + inputs: functionParams.inputs, + outputs: functionParams.outputs + }; + + return new OffchainFragment(params); + } + + static isOffchainFragment(value: any): value is OffchainFragment { + return (value && value._isFragment && value.type === FragmentType.Offchain); + } + + outputs?: Array; + + format(format?: FormatTypes): string { + if (!format) { + format = FormatTypes.Sighash; + } + + if (format === FormatTypes.Json) { + return JSON.stringify({ + type: FragmentType.Offchain, + name: this.name, + inputs: this.inputs.map(input => JSON.parse(input.format(format))), + outputs: this.outputs.map(output => JSON.parse(output.format(format))) + }); + } + + let result = ''; + + if (format !== FormatTypes.Sighash) { + result += 'getter '; + } + + result += `${ this.name }(${ this.inputs.map(input => input.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') }) `; + + if (format !== FormatTypes.Sighash) { + if (this.outputs && this.outputs.length) { + result += `returns (${ this.outputs.map(output => output.format(format)).join(', ') }) `; + } + } + + return result.trim(); + } +} + +interface _DefaultFragment extends _Fragment { + stateMutability: string; + payable: boolean; +} + +export class DefaultFragment extends Fragment implements _DefaultFragment { + static from(value: Fragment | JsonFragment | string): Fragment { + if (typeof (value) === 'string') { + return DefaultFragment.fromString(value); + } + return DefaultFragment.fromObject(value); + } + + static fromObject(value: Fragment | JsonFragment): Fragment { + if (Fragment.isFragment(value)) { + return value; + } + + if (!Object.values(FragmentType).includes(value.type as FragmentType)) { + throw new Error(`invalid fragment object ${ value }`); + } + + const state = verifyState(value); + + const params: TypeCheck<_DefaultFragment> = { + type: value.type, + name: value.name ? value.name : undefined, + inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), + payable: state.payable, + stateMutability: state.stateMutability + }; + + return new DefaultFragment(params); + } + + static fromString(value: string): Fragment { + const params: any = {}; + + const parens = value.match(regexParen); + const type = parens && parens[1].trim(); + + if (!Object.values(FragmentType).includes(type as FragmentType)) { + throw new Error(`invalid fragment object ${ value }`); + } + + params.type = type; + params.inputs = parseParams(parens[2].trim(), false); + + parseModifiers(parens[3].trim(), params); + + return DefaultFragment.fromObject(params); + } + + stateMutability: string; + payable: boolean; + + format(format?: FormatTypes): string { + if (!format) { + format = FormatTypes.Sighash; + } + + if (format === FormatTypes.Json) { + return JSON.stringify({ + type: this.type, + name: this.name ? this.name : undefined, + stateMutability: ((this.stateMutability === 'nonpayable') ? undefined : this.stateMutability), + payable: this.payable, + inputs: this.inputs.map(input => JSON.parse(input.format(format))) + }); + } + + let result = ''; + + if ([ FragmentType.Receive, FragmentType.Fallback, FragmentType.Constructor ].includes(this.type as FragmentType)) { + // allow sighash + result = `${ this.type }(${ this.inputs.map(input => input.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') }) `; + } else { + if (format !== FormatTypes.Sighash) { + result += `${ this.type } `; + } + + result += `${ this.name }(${ this.inputs.map(input => input.format(format)).join((format === FormatTypes.Full) ? ', ' : ',') }) `; + } + + if (format !== FormatTypes.Sighash) { + if (this.stateMutability) { + if (this.stateMutability !== 'nonpayable') { + result += (`${ this.stateMutability } `); + } + } + } + + return result.trim(); + } +} + +function verifyType(type: string): string { + // These need to be transformed to their full description + if (type.match(/^uint($|[^1-9])/)) { + type = `uint256${ type.substring(4) }`; + } else if (type.match(/^int($|[^1-9])/)) { + type = `int256${ type.substring(3) }`; + } + + const isArray = /^\w+(\[\d*\])+$/g.test(type); + const isPrimitive = /^\w+\d*$/g.test(type); + if (!isArray && !isPrimitive) { + throw new Error(`illegal type: ${ type }`); + } + + const _type = type.match(/^[a-zA-Z]+/g); + const baseType = _type && _type[0]; + if (!baseType || typePrefix.indexOf(baseType) === -1) { + throw new Error(`illegal type: ${ type }`); + } + + let _size; + if (isArray) { + _size = type.split('[')[0].match(getNum); + } else { + _size = type.match(getNum); + } + const size = _size ? _size[0] : 0; + + // bytes + if (baseType === 'bytes' && size && !(size > 0 && size <= 32)) { + throw new Error(`illegal type: ${ type }. Binary type of M bytes, 0 < M <= 32. Or dynamic sized byte sequence.`); + } + + // int + if ((baseType === 'int' || baseType === 'uint') && size && !(size > 0 && size <= 256 && size % 8 === 0)) { + throw new Error(`illegal type: ${ type }. Unsigned integer type of M bits, 0 < M <= 256, M % 8 == 0. e.g. uint32, uint8, uint256.`); + } + + return type; +} + +const typePrefix = [ 'uint', 'int', 'address', 'bool', 'bytes', 'string', 'tokenId', 'gid', 'tuple' ]; +const getNum = new RegExp(/(\d+)/g); +const regexIdentifier = new RegExp('^[a-zA-Z$_][a-zA-Z0-9$_]*$'); + +function verifyIdentifier(value: string): string { + if (!value || !value.match(regexIdentifier)) { + throw new Error(`invalid identifier: ${ value }`); + } + return value; +} + +const regexParen = new RegExp('^([^)(]*)\\((.*)\\)([^)(]*)$'); + +function splitNesting(value: string): Array { + value = value.trim(); + + const result = []; + let accum = ''; + let depth = 0; + for (let offset = 0; offset < value.length; offset++) { + const c = value[offset]; + if (c === ',' && depth === 0) { + result.push(accum); + accum = ''; + } else { + accum += c; + if (c === '(') { + depth++; + } else if (c === ')') { + depth--; + if (depth === -1) { + throw new Error(`unbalanced parenthesis ${ value }`); + } + } + } + } + if (accum) { + result.push(accum); + } + + return result; +} diff --git a/src/abi/index.ts b/src/abi/index.ts index 492aa17b..923dbdc0 100644 --- a/src/abi/index.ts +++ b/src/abi/index.ts @@ -1,139 +1,154 @@ import { isArray, isObject } from '~@vite/vitejs-utils'; -import { encodeFunction, getFunction } from './encodeFunction'; -import { encodeParameter as _encodeParameter, encodeParameters as _encodeParameters, decodeParameter as _decodeParameter, decodeParameters as _decodeParameters } from './coder'; -import { getTypes } from './inputsType'; +import { defaultAbiCoder } from './abicoder'; +import { Abi } from './abi'; +import { Fragment, JsonFragment, JsonParamType, ParamType } from './fragments'; +import * as utils from './utils'; +export type AbiFragment = Fragment | JsonFragment | string; +export type AbiParam = ParamType | JsonParamType | string; +export { Abi, utils }; -export function encodeLogSignature(jsonFunction, methodName?: string) { - return encodeFunction(jsonFunction, methodName); +export function encodeLogSignature(abiFragment: Array | AbiFragment, eventName?: string): string { + return Abi.from(abiFragment).getEventTopic(eventName); } -export function encodeFunctionSignature(jsonFunction, methodName?: string) { - const result = encodeFunction(jsonFunction, methodName); - return result.slice(0, 8); + +export function encodeFunctionSignature(abiFragment: Array | AbiFragment, methodName?: string) { + return Abi.from(abiFragment).getSighash(methodName); } -export function encodeFunctionCall(jsonInterface, params, methodName?: string) { - return encodeFunctionSignature(jsonInterface, methodName) + encodeParameters(jsonInterface, params, methodName); +export function encodeFunctionCall(abiFragment: Array | AbiFragment, params?: Array, methodName?: string) { + return Abi.from(abiFragment).encodeFunctionData(methodName, params); } -export function encodeParameter(type, param) { - return _encodeParameter(type, param).result; +export function decodeFunctionCall(abiFragment: Array | AbiFragment, data: string, methodName?: string) { + return Abi.from(abiFragment).decodeFunctionData(methodName, data); } -export const decodeParameter = _decodeParameter; -export function encodeParameters(types, params, methodName?: string) { - try { - if (methodName || !isArray(types) && isObject(types)) { - const func = getFunction(types, methodName); - types = getTypes(func); - } - } catch (err) { - // Do nothing - } +export function decodeFunctionOutput(abiFragment: Array | AbiFragment, data: string, methodName?: string) { + return Abi.from(abiFragment).decodeFunctionResult(methodName, data); +} - return _encodeParameters(getTypes(types), params); +export function encodeOffchainCall(abiFragment: Array | AbiFragment, params?: Array, methodName?: string) { + return Abi.from(abiFragment).encodeOffchainData(methodName, params); } -export function decodeParameters(types, params, methodName?: string) { - try { - if (methodName || !isArray(types) && isObject(types)) { - const func = getFunction(types, methodName); - types = getTypes(func); - } - } catch (err) { - // Do nothing - } - return _decodeParameters(getTypes(types), params); -} - -export function decodeLog(abi, data = '', topics, methodName?: string) { - const nonIndexedInputs = []; - const nonIndexedTypes = []; - const inputs = getInputs(abi, methodName); - const returnValues = {}; - let topicIndex = abi.anonymous ? 0 : 1; // for non-anonymous events, topics[0] always refers to the hash of the event signature - inputs.forEach((input, i) => { - if (input.indexed) { - // parse indexed params from topics - // if it's a reference type such as a string for an indexed argument, the blake2b hash of the value is stored as a topic instead. - const param = ([ 'bool', 'int', 'uint', 'address', 'fixed', 'ufixed', 'tokenId' ].find(function (staticType) { - return input.type.indexOf(staticType) !== -1; - })) ? decodeParameter(input.type, topics[topicIndex]) : topics[topicIndex]; - topicIndex++; - // add the indexed param to the return values - returnValues[i] = param; - if (input.name) returnValues[input.name] = param; - } else { - nonIndexedInputs.push(input); - nonIndexedTypes.push(input.type); - } - }); - // parse non-indexed params from data - const nonIndexedParams = decodeParameters(nonIndexedTypes, data); - // add non-indexed params to the return values - let index = 0; - inputs.forEach((input, i) => { - if (!input.indexed) { - returnValues[i] = nonIndexedParams[index]; - if (input.name) returnValues[input.name] = nonIndexedParams[index]; - index++; - } - }); - return returnValues; +export function decodeOffchainOutput(abiFragment: Array | AbiFragment, data: string, methodName?: string) { + return Abi.from(abiFragment).decodeOffchainResult(methodName, data); } -export function getAbiByType(jsonInterfaces, type) { - if (!jsonInterfaces || !type) { +export function encodeConstructor(abiFragment: Array | AbiFragment, params?: Array) { + return Abi.from(abiFragment).encodeDeploy(params); +} + +export function encodeParameter(type: AbiParam, param: any) { + return defaultAbiCoder.encode([ParamType.from(type)], [param]); +} + +export function decodeParameter(type: AbiParam, data: string) { + return defaultAbiCoder.decode([ParamType.from(type)], data)[0]; +} + +export function encodeParameters(types: Array | AbiParam | AbiFragment, params?: Array, methodName?: string) { + return defaultAbiCoder.encode(getTypes(types, methodName), params || []); +} +export function decodeParameters(types: Array | AbiParam | AbiFragment, data: string, methodName?: string) { + return defaultAbiCoder.decode(getTypes(types, methodName), data); +} + +export function decodeLog(abiFragment: Array | AbiFragment, data = '', topics: Array, eventName?: string) { + return Abi.from(abiFragment).decodeEventLog(eventName, data, topics); +} + +export function encodeLogFilter(abiFragment: Array | AbiFragment, values: Array, eventName?: string) { + return Abi.from(abiFragment).encodeFilterTopics(eventName, values); +} + +/** + * Return matched JSON fragment according to type, or return null if the type is not found + * @param jsonFragment + * @param type + * @return JsonFragment + */ +export function getAbiByType(jsonFragment: Array | JsonFragment, type: string): JsonFragment { + if (!jsonFragment || !type) { return null; } - if (!(isArray(jsonInterfaces) || isObject(jsonInterfaces))) { - throw new Error('jsonInterfaces need array or object '); + if (!(isArray(jsonFragment) || isObject(jsonFragment))) { + throw new Error('jsonFragment should be an array or object'); } - // jsonInterfaces is an object - if (!isArray(jsonInterfaces) && isObject(jsonInterfaces)) { - if (jsonInterfaces.type === type) { - return jsonInterfaces; - } + // jsonFragment is an object + if (!Array.isArray(jsonFragment)) { + return (jsonFragment.type === type) ? jsonFragment : null; } - // jsonInterfaces is an array - return jsonInterfaces.find(e => e.type === type) || null; + // jsonFragment is an array + return jsonFragment.find(item => item.type === type) || null; } -export function getAbiByName(jsonInterfaces, methodName) { - if (!jsonInterfaces || !methodName) { +/** + * Return matched JSON fragment according to method name, or return null if the method is not found + * @param jsonFragment + * @param methodName + * @return JsonFragment + */ +export function getAbiByName(jsonFragment: Array | JsonFragment, methodName: string): JsonFragment { + if (!jsonFragment || !methodName) { return null; } - if (!(isArray(jsonInterfaces) || isObject(jsonInterfaces))) { - throw new Error('jsonInterfaces need array or object '); + if (!(isArray(jsonFragment) || isObject(jsonFragment))) { + throw new Error('jsonFragment should be an array or object'); } - // jsonInterfaces is an object - if (!isArray(jsonInterfaces) && isObject(jsonInterfaces)) { - if (jsonInterfaces.name === methodName) { - return jsonInterfaces; - } + // jsonFragment is an object + if (!Array.isArray(jsonFragment)) { + return (jsonFragment.name === methodName) ? jsonFragment : null; } - // jsonInterfaces is an array - return jsonInterfaces.find(e => e.name === methodName) || null; + // jsonFragment is an array + return jsonFragment.find(item => item.name === methodName) || null; } -function getInputs(inputs, methodName?: string) { - try { - const func = getFunction(inputs, methodName); - func && (inputs = func); - } catch (err) { - // Do nothing - } +// Parse input fragments or types and return matched type array +function getTypes(types: Array | ParamType | AbiFragment, methodName?: string): Array { + const _types: Array = [ ]; + const _frags: Array = [ ]; + + const _parseInput = (inputs: any, _types: Array, _frags: Array): void => { + if (typeof (inputs) === 'string') { + const jsonParam: JsonParamType = utils.safeParseJson(inputs); + if (jsonParam) { // is json + inputs = jsonParam; + } + } + if (!Array.isArray(inputs)) { + try { + _types.push(ParamType.from(inputs)); + return; + } catch (e) { + try { + _frags.push(Fragment.from(inputs)); + return; + } catch (e) { + throw new Error(`invalid type or fragment ${ inputs }`); + } + } + } + inputs.forEach(item => _parseInput(item, _types, _frags)); + }; - if (!isArray(inputs) && !isObject(inputs)) { - throw new Error(`[Error] decodeLog: Illegal inputs ${ JSON.stringify(inputs) }. Should be Array or JsonInterface.`); - } + _parseInput(types, _types, _frags); - inputs = isArray(inputs) ? inputs : inputs.inputs; - return inputs || []; + if (methodName) { // fragment array + methodName + const result = _frags.find(item => item.name === (item.type === 'callback' ? `${ methodName }Callback` : methodName))?.inputs; + return result ? result : []; + } + if (_frags.length === 1) { + return _frags[0].inputs; + } else if (_frags.length > 1) { + throw new Error('missing method name'); + } + return _types; } diff --git a/src/abi/inputsType.ts b/src/abi/inputsType.ts deleted file mode 100644 index 5c87a88b..00000000 --- a/src/abi/inputsType.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { isArray, isObject } from '~@vite/vitejs-utils'; - -const ADDR_SIZE = 21; -const getNum = new RegExp(/(\d+)/g); -const typePre = [ 'uint', 'int', 'address', 'bool', 'bytes', 'string', 'tokenId', 'gid' ]; - -function formatType(typeStr) { - const { isArr, type, size } = validType(typeStr); - - const arrLen = []; - let isDynamic = type === 'string'; - if (isArr) { - const _typeStrArr = typeStr.split('[').slice(1); - if (_typeStrArr.length > 1) { - console.warn(`Not support [][][] like ${ typeStr }, now.`); - } - _typeStrArr.forEach(_tArr => { - const _len = _tArr.match(/\d+/g); - const len = _len && _len[0] ? _len[0] : 0; - isDynamic = isDynamic || !len; - arrLen.push(len); - }); - } - - let byteLength = size || 0; - switch (type) { - case 'number': - byteLength = size / 8 || 32; - break; - case 'bool': - byteLength = 1; - break; - case 'address': - byteLength = ADDR_SIZE; - break; - case 'gid': - case 'tokenId': - byteLength = 10; - break; - } - - return { - typeStr, - type, - byteLength: Math.ceil(byteLength / 32) * 32, - actualByteLen: byteLength, - isArr, - arrLen, - isDynamic: isDynamic || (type === 'bytes' && !byteLength) - }; -} - -function validType(typeStr) { - if (typeof typeStr !== 'string') { - throw new Error(`[Error] Illegal type ${ JSON.stringify(typeStr) }. Should be type-string, like \'uint32\'.`); - } - - const isArr = /^\w+(\[\d*\])+$/g.test(typeStr); - const isSingle = /^\w+\d*$/g.test(typeStr); - if (!isArr && !isSingle) { - throw new Error(`[Error] Illegal type. ${ typeStr }`); - } - - const _type = typeStr.match(/^[a-zA-Z]+/g); - let type = _type && _type[0] ? _type[0] : ''; - if (!type || typePre.indexOf(type) === -1) { - throw new Error(`[Error] Illegal type. ${ typeStr }`); - } - - // int uint ==> number - type = type.indexOf('int') >= 0 ? 'number' : type; - - let _size; - if (isArr) { - const _typeStrArr = typeStr.split('['); - _size = _typeStrArr[0].match(getNum); - } else { - _size = typeStr.match(getNum); - } - const size = _size ? _size[0] : 0; - - // bytes - if (type === 'bytes' && size && !(size > 0 && size <= 32)) { - throw new Error(`[Error] Illegal type. ${ typeStr }: Binary type of M bytes, 0 < M <= 32. Or dynamic sized byte sequence.`); - } - - // int - if (type === 'number' && size && !(size > 0 && size <= 256 && size % 8 === 0)) { - throw new Error(`[Error] Illegal type. ${ typeStr }: Unsigned integer type of M bits, 0 < M <= 256, M % 8 == 0. e.g. uint32, uint8, uint256.`); - } - - return { isArr, type, size }; -} - -function getTypes(jsonInterface) { - if (isArray(jsonInterface)) { - const types = []; - jsonInterface && jsonInterface.forEach(function (param) { - const type = typeof param === 'string' ? param : param.type; - validType(type); - types.push(type); - }); - return types; - } - - if (!isObject(jsonInterface)) { - throw new Error(`[Error] Illegal types: ${ jsonInterface }. Should be Array or JsonInterface.`); - } - - const types = []; - jsonInterface.inputs && jsonInterface.inputs.forEach(function (param) { - validType(param.type); - types.push(param.type); - }); - return types; -} - -export { validType, formatType, getTypes }; diff --git a/src/abi/utils.ts b/src/abi/utils.ts new file mode 100644 index 00000000..519aff31 --- /dev/null +++ b/src/abi/utils.ts @@ -0,0 +1,178 @@ +import { isHexString } from '~@vite/vitejs-utils'; + +const HexCharacters = '0123456789abcdef'; + +/** + * Convert a given value into hex string + * @param value + */ +export function hexlify(value: Buffer | Uint8Array | string | number | bigint): string { + if (typeof (value) === 'number') { + if (value < 0 || value >= 0x1fffffffffffff) { + throw new Error(`invalid hexlify value ${ value }`); + } + let hex = ''; + while (value) { + hex = HexCharacters[value & 0xf] + hex; + value = Math.floor(value / 16); + } + if (hex.length) { + if (hex.length % 2) { + hex = `0${ hex }`; + } + return `${ hex }`; + } + return '00'; + } + if (typeof (value) === 'bigint') { + if (value < 0) { + throw new Error(`invalid hexlify value ${ value }`); + } + value = value.toString(16); + if (value.length % 2) { + return (`0${ value }`); + } + return `${ value }`; + } + if (typeof (value) === 'string') { + if (value.substring(0, 2) === '0x') { + value = value.substring(2); + } + if (isHexString(value)) { + if (value.length % 2) { + throw new Error(`hex data is odd-length ${ value }`); + // value = `0${ value }`; + } + return value; + } + throw new Error(`not hex string ${ value }`); + } + if (Buffer.isBuffer(value)) { + return value.toString('hex'); + } + if (value.constructor === Uint8Array) { + return Buffer.from(value).toString('hex'); + } + + throw new Error(`invalid hexlify value ${ value }`); +} + +/** + * Convert a given value into byte array + * @param value + */ +export function arrayify(value: Buffer | Uint8Array | string | number | bigint): Buffer { + if (typeof (value) === 'number') { + if (value < 0 || value >= 0x1fffffffffffff) { + throw new Error(`invalid arrayify value ${ value }`); + } + const result = []; + while (value) { + result.unshift(value & 0xff); + value = parseInt(String(value / 256)); + } + if (result.length === 0) { + result.push(0); + } + + return Buffer.from(result); + } + if (typeof (value) === 'bigint') { + if (value < 0) { + throw new Error(`invalid arrayify value ${ value }`); + } + value = value.toString(16); + if (value.length % 2) { + value = `0${ value }`; + } + return Buffer.from(value.toString(), 'hex'); + } + if (typeof (value) === 'string') { + if (value.substring(0, 2) === '0x') { + value = value.substring(2); + } + if (isHexString(value)) { + if (value.length % 2) { + value = `0${ value }`; + } + return Buffer.from(value.toString(), 'hex'); + } + throw new Error(`not hex string ${ value }`); + } + + if (Buffer.isBuffer(value) || (value as any).constructor === Uint8Array) { + // return Buffer.alloc(value.length, value); + return Buffer.from(value); + } + + throw new Error(`invalid arrayify value ${ value }`); +} + +/** + * Pad a hex string with zeros on the left + * @param value + * @param length The length of the returned string in bytes + */ +export function leftPadZero(value: Buffer | string, length: number): string { + if (typeof (value) !== 'string') { + value = hexlify(value); + } else if (!isHexString(value)) { + throw new Error(`invalid hex string: ${ value }`); + } + + if (value.length > 2 * length) { + throw new Error(`value out of range: ${ value }, length: ${ length }`); + } + + while (value.length < 2 * length) { + value = `0${ value }`; + } + + return value; +} + +/** + * Pad a hex string with zeros on the right + * @param value + * @param length The length of the returned string in bytes + */ +export function rightPadZero(value: Buffer | string, length: number): string { + if (typeof (value) !== 'string') { + value = hexlify(value); + } else if (!isHexString(value)) { + throw new Error(`invalid hex string: ${ value }`); + } + + if (value.length > 2 * length) { + throw new Error(`value out of range: ${ value }, length: ${ length }`); + } + + while (value.length < 2 * length) { + value = `${ value }0`; + } + + return value; +} + +/** + * Parse a string into JSON object. When the input is not valid JSON string, this function returns null instead of throwing an error. + * @param value + */ +export function safeParseJson(value: any) { + if (typeof value !== 'string') return null; + try { + const result = JSON.parse(value); + const type = Object.prototype.toString.call(result); + return (type === '[object Object]' || type === '[object Array]') ? result : null; + } catch (err) { + return null; + } +} + +/** + * Determine an array's maximum depth. Returns 0 if the input is not an array. + * @param value + */ +export function getArrayDepth(value: any) { + return Array.isArray(value) ? 1 + Math.max(0, ...value.map(getArrayDepth)) : 0; +} diff --git a/src/accountBlock/utils.ts b/src/accountBlock/utils.ts index 33472195..ae75a5c6 100644 --- a/src/accountBlock/utils.ts +++ b/src/accountBlock/utils.ts @@ -3,11 +3,20 @@ const blake = require('blakejs/blake2b'); import { paramsMissing, paramsFormat } from '~@vite/vitejs-error'; import { Delegate_Gid, Contracts } from '~@vite/vitejs-constant'; -import { getAbiByType, encodeParameters, encodeFunctionCall, encodeFunctionSignature, decodeLog } from '~@vite/vitejs-abi'; +import { + getAbiByType, + encodeParameters, + encodeFunctionCall, + encodeFunctionSignature, + decodeLog, + AbiFragment, + decodeFunctionCall +} from '~@vite/vitejs-abi'; import { isValidAddress, getAddressFromPublicKey, createAddressByPrivateKey, getOriginalAddressFromAddress, AddressType, getAddressFromOriginalAddress } from '~@vite/vitejs-wallet/address'; import { checkParams, isNonNegativeInteger, isHexString, isValidTokenId, getOriginalTokenIdFromTokenId, isObject, ed25519, isBase64String } from '~@vite/vitejs-utils'; import { BlockType, Address, Base64, Hex, TokenId, Uint64, BigInt, AccountBlockType, Uint8 } from './type'; +import { EventFragment, Fragment, FunctionFragment } from '../abi/fragments'; export const Default_Hash = '0000000000000000000000000000000000000000000000000000000000000000'; // A total of 64 0 @@ -377,7 +386,7 @@ export function getTriggeredSendBlockListHex(triggeredSendBlockList: AccountBloc // Get AccountBlock.data -export function getCreateContractData({ abi, code, params, responseLatency = '0', quotaMultiplier = '10', randomDegree = '0' }: { +export function getCreateContractData({ abi, code, params = [], responseLatency = '0', quotaMultiplier = '10', randomDegree = '0' }: { responseLatency?: Uint8; quotaMultiplier?: Uint8; randomDegree?: Uint8; @@ -410,7 +419,7 @@ export function getCreateContractData({ abi, code, params, responseLatency = '0' let data = `${ Delegate_Gid }01${ Buffer.from(_responseLatency).toString('hex') }${ Buffer.from(_randomDegree).toString('hex') }${ Buffer.from(_quotaMultiplier).toString('hex') }${ code }`; if (jsonInterface) { - data += encodeParameters(jsonInterface, params); + data += encodeParameters(jsonInterface, Array.isArray(params) ? params : [params]); } return Buffer.from(data, 'hex').toString('base64'); } @@ -485,7 +494,7 @@ export function signAccountBlock(accountBlock: { export function decodeContractAccountBlock({ accountBlock, contractAddress, abi, topics = [], methodName }: { accountBlock: AccountBlockType; contractAddress: Address; - abi: any; + abi: AbiFragment; topics?: any; methodName?: string; }) { @@ -512,7 +521,7 @@ export function decodeContractAccountBlock({ accountBlock, contractAddress, abi, export function decodeAccountBlockDataByContract({ data, abi, topics = [], methodName }: { data: Base64; - abi: any; + abi: AbiFragment; topics?: any; methodName?: string; }) { @@ -530,8 +539,13 @@ export function decodeAccountBlockDataByContract({ data, abi, topics = [], metho if (encodeFuncSign !== hexData.substring(0, 8)) { return null; } - - return decodeLog(abi, hexData.substring(8), topics, methodName); + const _abi = Fragment.from(abi); + if (FunctionFragment.isFunctionFragment(_abi)) { + return decodeFunctionCall(_abi, hexData, methodName); + } else if (EventFragment.isEventFragment(_abi)) { + return decodeLog(_abi, hexData, topics, methodName); + } + throw new Error(`unsupported abi type ${ _abi.type }`); } // contractList = { 'transactionTypeName': { contractAddress, abi } } diff --git a/src/utils/index.ts b/src/utils/index.ts index 662f1ed2..aad3ed3f 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,11 +1,11 @@ -const bn = require('bn.js'); -const blake = require('blakejs/blake2b'); - -import { paramsMissing, paramsFormat } from '~@vite/vitejs-error'; +import { paramsFormat, paramsMissing } from '~@vite/vitejs-error'; import * as _e from './ed25519'; import { Hex, TokenId } from './type'; +const bn = require('bn.js'); +const blake = require('blakejs/blake2b'); + declare const enum Charset { 'utf16' = 'utf16', 'utf8' = 'utf8' @@ -173,8 +173,21 @@ export function isSafeInteger(num): -1 | 0 | 1 { return 1; } -export function isHexString(str: string): boolean { - return /^[0-9a-fA-F]+$/.test(str); +/** + * Determine if the input is a hex string. The 2nd argument is to check if a hex string meets the specified length in bytes, + * if not the function will return false. + * @param str + * @param length in bytes + */ +export function isHexString(str: string, length?: number): boolean { + // return /^[0-9a-fA-F]+$/.test(str); + if (typeof (str) !== 'string' || !str.match(/^[0-9A-Fa-f]*$/)) { + return false; + } + if (length && str.length !== 2 * length) { + return false; + } + return true; } export function isBase64String(str): boolean { diff --git a/test/RPC/dex.js b/test/RPC/dex.js index 59bd46c3..0e085c72 100644 --- a/test/RPC/dex.js +++ b/test/RPC/dex.js @@ -5,18 +5,20 @@ import { sleep, SendTXByPreviousAccountBlock, viteProvider, privateKey, address, export default async function TestFunc() { console.log('Step 0 DEX Test Start. \n'); - console.log('Step 1 Get balance. \n'); - await GetBalance(); - let previousAccountBlock = null; // 1. Deposit-Withdraw - console.log('Step 2 Deposit. \n'); + console.log('Step 1 Deposit. \n'); previousAccountBlock = await Deposit(); await sleep(2000); + console.log('Step 2 Get balance. \n'); + await GetBalance(); + + await sleep(2000); + console.log('Step 3 Withdraw. \n'); previousAccountBlock = await Withdraw(previousAccountBlock); @@ -130,7 +132,7 @@ async function GetBalance() { async function Deposit() { const accountBlock = await tx.dexDeposit({ - toAddress: address, + toAddress: address, tokenId: Vite_TokenId, amount: '300000000000000000000000' }); @@ -142,7 +144,7 @@ async function Deposit() { async function Withdraw(previousAccountBlock) { const accountBlock = await tx.dexWithdraw({ - toAddress: address, + toAddress: address, tokenId: Vite_TokenId, amount: '1000000000000000000' }); diff --git a/test/RPC/wallet.js b/test/RPC/wallet.js index 0958b621..62c0a037 100644 --- a/test/RPC/wallet.js +++ b/test/RPC/wallet.js @@ -58,10 +58,12 @@ export default async function TestFunc() { console.log('Step 13 CreateContract. \n'); accountBlock = await CreateContract(accountBlock); + await sleep(2000); + console.log('Step 14 CheckTokenList. \n'); accountBlock = await CheckTokenList(accountBlock); await sleep(2000); - console.log('Step 14 CancelQuotaStake. \n'); + console.log('Step 15 CancelQuotaStake. \n'); accountBlock = await CancelQuotaStake(accountBlock); console.log('Last One CheckTxList. \n'); @@ -82,7 +84,7 @@ async function CheckBalance() { const balance = data.balance; const unreceived = data.unreceived; - + console.log('[LOG] CheckMyBalance unreceived', unreceived, '\n'); if (balance && Number(balance.totalNumber)) { @@ -97,7 +99,7 @@ async function CheckBalance() { async function CheckQuota(previousAccountBlock) { const quotaResult = await viteProvider.request('contract_getQuotaByAccount', address); console.log('[LOG] contract_getQuotaByAccount', quotaResult, '\n'); - + if (Number(quotaResult.currentQuota)) { return previousAccountBlock; } @@ -126,7 +128,7 @@ async function CheckQuota(previousAccountBlock) { async function SendTxToMyself(previousAccountBlock) { const accountBlock = await tx.send({ - toAddress: address, + toAddress: address, tokenId: Vite_TokenId, amount: '10000000000000000000' }); @@ -187,7 +189,7 @@ async function UpdateSBPBlockProducingAddress(previousAccountBlock) { sbpName: 'CS_TEST_NODE', blockProducingAddress: 'vite_869a06b8963bd5d88a004723ad5d45f345a71c0884e2c80e88' }); - + const result = await SendTXByPreviousAccountBlock(accountBlock, previousAccountBlock); console.log('[LOG] UpdateSBPBlockProducingAddress', result, '\n'); return result; @@ -196,7 +198,7 @@ async function UpdateSBPBlockProducingAddress(previousAccountBlock) { async function WithdrawSBPReward(previousAccountBlock) { const accountBlock = tx.withdrawSBPReward({ sbpName:'CS_TEST_NODE', - receiveAddress: address + receiveAddress: address }); const result = await SendTXByPreviousAccountBlock(accountBlock, previousAccountBlock); @@ -206,7 +208,7 @@ async function WithdrawSBPReward(previousAccountBlock) { async function RevokeSBP(previousAccountBlock) { const accountBlock = tx.revokeSBP({ - sbpName:'CS_TEST_NODE' + sbpName:'CS_TEST_NODE' }); const result = await SendTXByPreviousAccountBlock(accountBlock, previousAccountBlock); @@ -256,7 +258,7 @@ async function CancelQuotaStake(previousAccountBlock) { let backQuota = list.stakeList[0]; - const accountBlock = null; + let accountBlock = null; if (!backQuota.id) { console.log('[LOG] cancelQuotaStake_V2 no id', backQuota, '\n'); @@ -330,14 +332,23 @@ async function CheckTokenList(previousAccountBlock) { console.log('Step 13 IssueToken 1. \n'); previousAccountBlock = await IssueToken(previousAccountBlock); + await sleep(2000); + previousAccountBlock = await ReceiveTx(previousAccountBlock); + await sleep(2000); console.log('Step 13 IssueToken 2. \n'); previousAccountBlock = await IssueToken(previousAccountBlock); + await sleep(2000); + previousAccountBlock = await ReceiveTx(previousAccountBlock); + await sleep(2000); console.log('Step 13 IssueToken 3. \n'); previousAccountBlock = await IssueToken(previousAccountBlock); + await sleep(2000); + previousAccountBlock = await ReceiveTx(previousAccountBlock); + await sleep(2000); tokens = await viteProvider.request('contract_getTokenInfoListByOwner', address); console.log('[LOG] contract_getTokenInfoListByOwner Again', tokens, '\n'); @@ -362,7 +373,10 @@ async function CheckTokenList(previousAccountBlock) { if (reIssueOne) { await sleep(2000); previousAccountBlock = await ReIssueToken(previousAccountBlock, reIssueOne); - + + await sleep(2000); + previousAccountBlock = await ReceiveTx(previousAccountBlock); + await sleep(2000 * 3); previousAccountBlock = await BurnToken(previousAccountBlock, reIssueOne); } @@ -382,12 +396,12 @@ async function CheckTokenList(previousAccountBlock) { async function IssueToken(previousAccountBlock) { const accountBlock = await tx.issueToken({ - tokenName: 'cstestToken', - isReIssuable: true, - maxSupply: '10000000000000000000000000', - isOwnerBurnOnly: false, - totalSupply: '100000000000000000000000', - decimals: 2, + tokenName: 'cstestToken', + isReIssuable: true, + maxSupply: '10000000000000000000000000', + isOwnerBurnOnly: false, + totalSupply: '100000000000000000000000', + decimals: 2, tokenSymbol: 'CSTT' }); diff --git a/test/packages/abi.js b/test/packages/abi.js index 70192826..6965f9db 100644 --- a/test/packages/abi.js +++ b/test/packages/abi.js @@ -1,1269 +1,2207 @@ +import { blake2bHex } from '~@vite/vitejs-utils'; + const assert = require('assert'); -import { type } from 'os'; import * as abi from '../../src/abi/index'; +import { + ConstructorFragment, + DefaultFragment, EventFragment, + FormatTypes, + Fragment, + FunctionFragment, OffchainFragment, + ParamType +} from '../../src/abi/fragments'; +import { arrayify, rightPadZero } from '../../src/abi/utils'; +import { ArrayCoder } from '../../src/abi/coder/array'; +import { StringCoder } from '../../src/abi/coder/string'; +import { TupleCoder } from '../../src/abi/coder/tuple'; +import { BytesCoder } from '../../src/abi/coder/bytes'; +import { AddressCoder } from '../../src/abi/coder/address'; +import { NumberCoder } from '../../src/abi/coder/number'; +import { GidCoder } from '../../src/abi/coder/gid'; +import { NullCoder } from '../../src/abi/coder/null'; +import { Writer, Reader } from '../../src/abi/coder'; -describe('encodeParameter', function () { - it('uint256', function () { - const _r = abi.encodeParameter('uint256', '2345675643'); - assert.equal('000000000000000000000000000000000000000000000000000000008bd02b7b', _r); - }); - it('uint', function () { - const _r1 = abi.encodeParameter('uint', '2345675643'); - assert.equal('000000000000000000000000000000000000000000000000000000008bd02b7b', _r1); - }); - it('tokenId', function () { - const result = abi.encodeParameter('tokenId', 'tti_5649544520544f4b454e6e40'); - assert.equal('000000000000000000000000000000000000000000005649544520544f4b454e', result); - }); - it('uint8', function () { - const encodeParameterResult1 = abi.encodeParameter('uint8', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult1); - }); - it('int 2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult1111); - }); - it('int -2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int', '-2'); - assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult1111); - }); - it('int -19999999999999999999999999999999999999999999999999999999999999', function () { - const encodeParameterResult1111 = abi.encodeParameter('int', '-19999999999999999999999999999999999999999999999999999999999999'); - assert.equal('fffffffffffff38dd0f10627f5529bdb2c52d4846810af0ac000000000000001', encodeParameterResult1111); - }); - it('bytes', function () { - const _xxx = abi.encodeParameter('bytes', '0xdf3234'); - assert.equal('00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000', _xxx); - }); - it('uint16', function () { - const encodeParameterResult3 = abi.encodeParameter('uint16', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult3); - }); - it('uint16[]', function () { - const encodeParameterResult4 = abi.encodeParameter('uint16[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult4); - }); - it('uint8[]', function () { - const encodeParameterResult2 = abi.encodeParameter('uint8[]', [ '1', '2' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult2); - }); - it('uint32', function () { - const encodeParameterResult5 = abi.encodeParameter('uint32', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult5); - }); - it('uint32[]', function () { - const encodeParameterResult6 = abi.encodeParameter('uint32[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult6); - }); - it('uint64', function () { - const encodeParameterResult7 = abi.encodeParameter('uint64', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult7); - }); - it('uint64[]', function () { - const encodeParameterResult8 = abi.encodeParameter('uint64[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult8); - }); - it('uint256', function () { - const encodeParameterResult9 = abi.encodeParameter('uint256', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult9); - }); - it('uint256[]', function () { - const encodeParameterResult10 = abi.encodeParameter('uint256[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult10); - }); - it('int8', function () { - const encodeParameterResult11 = abi.encodeParameter('int8', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult11); - }); - it('int8 -2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int8', '-2'); - assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult1111); - }); - it('int8[]', function () { - const encodeParameterResult12 = abi.encodeParameter('int8[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult12); - }); - it('int8[] -', function () { - const encodeParameterResult14 = abi.encodeParameter('int8[]', [ -2, -99 ]); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d', encodeParameterResult14); - }); - it('int16', function () { - const encodeParameterResult13 = abi.encodeParameter('int16', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult13); - }); - it('int16 -2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int16', '-2'); - assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult1111); - }); - it('int16[]', function () { - const encodeParameterResult14 = abi.encodeParameter('int16[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult14); - }); - it('int16[] -', function () { - const encodeParameterResult14 = abi.encodeParameter('int16[]', [ -2, -99 ]); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d', encodeParameterResult14); - }); +describe('abi', function () { + const _ = assert.deepEqual; - it('int32', function () { - const encodeParameterResult15 = abi.encodeParameter('int32', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult15); - }); - it('int32 -2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int32', '-2'); - assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult1111); - }); - it('int32[]', function () { - const encodeParameterResult16 = abi.encodeParameter('int32[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult16); - }); - it('int32[] -', function () { - const encodeParameterResult14 = abi.encodeParameter('int16[]', [ -2, -99 ]); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d', encodeParameterResult14); - }); - it('int64', function () { - const encodeParameterResult17 = abi.encodeParameter('int64', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult17); - }); - it('int64 -2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int64', '-2'); - assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult1111); - }); - it('int64[]', function () { - const encodeParameterResult18 = abi.encodeParameter('int64[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult18); + before(() => { + assert.deepEqual = (actual, expected, message) => { + if (Array.isArray(actual)) { + actual = actual.map(e => e); // remove additional name indexes + } + _(actual, expected, message); + }; }); - it('int256', function () { - const encodeParameterResult19 = abi.encodeParameter('int256', '2'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult19); - }); - it('int256 -2', function () { - const encodeParameterResult1111 = abi.encodeParameter('int256', '-2'); - assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult1111); + after(() => { + assert.deepEqual = _; }); - it('int256[]', function () { - const encodeParameterResult20 = abi.encodeParameter('int256[]', [ 1, 2 ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult20); - }); - it('bytes1', function () { - const encodeParameterResult21 = abi.encodeParameter('bytes1', '0x01'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult21); - }); - it('bytes2', function () { - const encodeParameterResult22 = abi.encodeParameter('bytes2', '0x0100'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult22); - }); - it('bytes3', function () { - const encodeParameterResult23 = abi.encodeParameter('bytes3', '0x010000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult23); - }); - it('bytes4', function () { - const encodeParameterResult24 = abi.encodeParameter('bytes4', '0x01000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult24); - }); - it('bytes5', function () { - const encodeParameterResult25 = abi.encodeParameter('bytes5', '0x0100000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult25); - }); - it('bytes6', function () { - const encodeParameterResult26 = abi.encodeParameter('bytes6', '0x010000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult26); - }); - it('bytes7', function () { - const encodeParameterResult27 = abi.encodeParameter('bytes7', '0x01000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult27); - }); - it('bytes8', function () { - const encodeParameterResult28 = abi.encodeParameter('bytes8', '0x0100000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult28); - }); - it('bytes9', function () { - const encodeParameterResult29 = abi.encodeParameter('bytes9', '0x010000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult29); - }); - it('bytes10', function () { - const encodeParameterResult30 = abi.encodeParameter('bytes10', '0x01000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult30); - }); - it('bytes11', function () { - const encodeParameterResult31 = abi.encodeParameter('bytes11', '0x0100000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult31); - }); - it('bytes12', function () { - const encodeParameterResult32 = abi.encodeParameter('bytes12', '0x010000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult32); - }); - it('bytes13', function () { - const encodeParameterResult33 = abi.encodeParameter('bytes13', '0x01000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult33); - }); - it('bytes14', function () { - const encodeParameterResult34 = abi.encodeParameter('bytes14', '0x0100000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult34); - }); - it('bytes15', function () { - const encodeParameterResult35 = abi.encodeParameter('bytes15', '0x010000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult35); - }); - it('bytes16', function () { - const encodeParameterResult36 = abi.encodeParameter('bytes16', '0x01000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult36); - }); - it('bytes17', function () { - const encodeParameterResult37 = abi.encodeParameter('bytes17', '0x0100000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult37); - }); - it('bytes18', function () { - const encodeParameterResult38 = abi.encodeParameter('bytes18', '0x010000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult38); - }); - it('bytes19', function () { - const encodeParameterResult39 = abi.encodeParameter('bytes19', '0x01000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult39); - }); - it('bytes20', function () { - const encodeParameterResult40 = abi.encodeParameter('bytes20', '0x0100000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult40); - }); - it('bytes21', function () { - const encodeParameterResult41 = abi.encodeParameter('bytes21', '0x010000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult41); - }); - it('bytes22', function () { - const encodeParameterResult42 = abi.encodeParameter('bytes22', '0x01000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult42); - }); - it('bytes23', function () { - const encodeParameterResult43 = abi.encodeParameter('bytes23', '0x0100000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult43); - }); - it('bytes24', function () { - const encodeParameterResult44 = abi.encodeParameter('bytes24', '0x010000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult44); - }); - it('bytes25', function () { - const encodeParameterResult46 = abi.encodeParameter('bytes25', '0x01000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult46); - }); - it('bytes26', function () { - const encodeParameterResult47 = abi.encodeParameter('bytes26', '0x0100000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult47); - }); - it('bytes27', function () { - const encodeParameterResult48 = abi.encodeParameter('bytes27', '0x010000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult48); - }); - it('bytes28', function () { - const encodeParameterResult49 = abi.encodeParameter('bytes28', '0x01000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult49); - }); - it('bytes29', function () { - const encodeParameterResult50 = abi.encodeParameter('bytes29', '0x0100000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult50); - }); - it('bytes30', function () { - const encodeParameterResult51 = abi.encodeParameter('bytes30', '0x010000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult51); - }); - it('bytes31', function () { - const encodeParameterResult52 = abi.encodeParameter('bytes31', '0x01000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult52); - }); - it('bytes32', function () { - const encodeParameterResult53 = abi.encodeParameter('bytes32', '0x0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000000000000000000000000000000000', encodeParameterResult53); - }); - it('address[]', function () { - const encodeParameterResult55 = abi.encodeParameter('address[]', [ 'vite_010000000000000000000000000000000000000063bef3da00', 'vite_0200000000000000000000000000000000000000e4194eedc2' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000', encodeParameterResult55); - }); - it('address', function () { - const encodeParameterResult5555 = abi.encodeParameter('address', 'vite_010000000000000000000000000000000000000063bef3da00'); - assert.equal('0000000000000000000000010000000000000000000000000000000000000000', encodeParameterResult5555); - }); - it('tokenId[]', function () { - const encodeParameterResult57 = abi.encodeParameter('tokenId[]', [ 'tti_01000000000000000000fb5e', 'tti_02000000000000000000199f' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000', encodeParameterResult57); - }); - it('gid[]', function () { - const encodeParameterResult56 = abi.encodeParameter('gid[]', [ '01000000000000000000', '02000000000000000000' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000', encodeParameterResult56); - }); - it('gid', function () { - const encodeParameterResult5666 = abi.encodeParameter('gid', '01000000000000000000'); - assert.equal('0000000000000000000000000000000000000000000001000000000000000000', encodeParameterResult5666); - }); - it('bool: 0000000000000000000000000000000000000000000000000000000000000001 is true', function () { - const encodeParameterResult5667 = abi.encodeParameter('bool', true); - assert.equal('0000000000000000000000000000000000000000000000000000000000000001', encodeParameterResult5667); - }); - it('bool: 0000000000000000000000000000000000000000000000000000000000000000 is false', function () { - const encodeParameterResult5667 = abi.encodeParameter('bool', false); - assert.equal('0000000000000000000000000000000000000000000000000000000000000000', encodeParameterResult5667); - }); - it('bytes32[]', function () { - const encodeParameterResult58 = abi.encodeParameter('bytes32[]', [ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000000000000000000000000000' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000', encodeParameterResult58); - }); - it('bytes32[] string', function () { - const encodeParameterResult58 = abi.encodeParameter('bytes32[]', JSON.stringify([ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000000000000000000000000000' ])); - assert.equal('000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000', encodeParameterResult58); - }); - it('bytes 0X', function () { - const encodeParameterResult5889 = abi.encodeParameter('bytes', '0xdf3234'); - assert.equal('00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000', encodeParameterResult5889); - }); - it('bytes', function () { - const encodeParameterResult5899 = abi.encodeParameter('bytes', 'df3234'); - assert.equal('00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000', encodeParameterResult5899); - }); - it('string foobar', function () { - const encodeParameterResult60 = abi.encodeParameter('string', 'foobar'); - assert.equal('0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000', encodeParameterResult60); - }); - it('string 0x02', function () { - const encodeParameterResult60 = abi.encodeParameter('string', '0x02'); - assert.equal('00000000000000000000000000000000000000000000000000000000000000043078303200000000000000000000000000000000000000000000000000000000', encodeParameterResult60); - }); - it('string 02ab', function () { - const encodeParameterResult60 = abi.encodeParameter('string', '02ab'); - assert.equal('00000000000000000000000000000000000000000000000000000000000000043032616200000000000000000000000000000000000000000000000000000000', encodeParameterResult60); - }); - it('uint8[2]', function () { - const encodeParameterResult6000 = abi.encodeParameter('uint8[2]', [ '1', '2' ]); - assert.equal('00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParameterResult6000); - }); - it('uint32[2][3][4]', function () { - // Not support - const encodeParameterResult54 = abi.encodeParameter('uint32[2][3][4]', [[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]]); - assert.equal('000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018', encodeParameterResult54); - }); - it('uint32[2][3][4] string', function () { - // Not support - const encodeParameterResult54 = abi.encodeParameter('uint32[2][3][4]', JSON.stringify([[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]])); - assert.equal('000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018', encodeParameterResult54); - }); - // it('bytes[][][]', function () { - // const encodeParameterResult65 = abi.encodeParameter('bytes[][][]', [[['0x0100000000000000000000000000000000000000000000000000000000000000'], [ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0100000000000000000000000000000000000000000000000000000000000000' ], ['0x0100000000000000000000000000000000000000000000000000000000000000']]]); - // assert.equal('', encodeParameterResult65); - // }); -}); - -describe('decodeParameter', function () { - it('tokenId', function () { - const result = abi.decodeParameter('tokenId', '000000000000000000000000000000000000000000005649544520544f4b454e'); - assert.equal('tti_5649544520544f4b454e6e40', result); - }); - it('uint8', function () { - const encodeParameterResult1 = abi.decodeParameter('uint8', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult1); - }); - it('bool: 0000000000000000000000000000000000000000000000000000000000000001 is decode to 1', function () { - const encodeParameterResult1 = abi.decodeParameter('bool', '0000000000000000000000000000000000000000000000000000000000000001'); - assert.equal('1', encodeParameterResult1); - }); - it('bool: 0000000000000000000000000000000000000000000000000000000000000000 is decode to 0', function () { - const encodeParameterResult1 = abi.decodeParameter('bool', '0000000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0', encodeParameterResult1); - }); - it('uint16', function () { - const encodeParameterResult3 = abi.decodeParameter('uint16', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult3); - }); - it('uint32', function () { - const encodeParameterResult5 = abi.decodeParameter('uint32', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult5); - }); - it('uint64', function () { - const encodeParameterResult7 = abi.decodeParameter('uint64', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult7); - }); - it('uint256', function () { - const encodeParameterResult9 = abi.decodeParameter('uint256', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult9); - }); - it('int8', function () { - const encodeParameterResult11 = abi.decodeParameter('int8', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult11); - }); - it('int8 -2', function () { - const encodeParameterResult1111 = abi.decodeParameter('int8', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); - assert.equal('-2', encodeParameterResult1111); - }); - it('int8[] -', function () { - const encodeParameterResult14 = abi.decodeParameter('int8[]', '0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); - assert.deepEqual([ -2, -99 ], encodeParameterResult14); - }); - it('int16', function () { - const encodeParameterResult13 = abi.decodeParameter('int16', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult13); - }); - it('int16 -2', function () { - const encodeParameterResult1111 = abi.decodeParameter('int16', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); - assert.equal('-2', encodeParameterResult1111); - }); - it('int16[] -', function () { - const encodeParameterResult14 = abi.decodeParameter('int16[]', '0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); - assert.deepEqual([ -2, -99 ], encodeParameterResult14); - }); - it('int32', function () { - const encodeParameterResult15 = abi.decodeParameter('int32', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult15); - }); - it('int32 -2', function () { - const encodeParameterResult1111 = abi.decodeParameter('int32', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); - assert.equal('-2', encodeParameterResult1111); - }); - it('int32[] -', function () { - const encodeParameterResult14 = abi.decodeParameter('int16[]', '0000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); - assert.deepEqual([ -2, -99 ], encodeParameterResult14); - }); - it('int64', function () { - const encodeParameterResult17 = abi.decodeParameter('int64', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult17); - }); - it('int64 -2', function () { - const encodeParameterResult1111 = abi.decodeParameter('int64', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); - assert.equal(-2, encodeParameterResult1111); - }); - it('int256', function () { - const encodeParameterResult19 = abi.decodeParameter('int256', '0000000000000000000000000000000000000000000000000000000000000002'); - assert.equal('2', encodeParameterResult19); - }); - it('int256 -2', function () { - const encodeParameterResult1111 = abi.decodeParameter('int256', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); - assert.equal(-2, encodeParameterResult1111); - }); - it('uint16[]', function () { - const encodeParameterResult4 = abi.decodeParameter('uint16[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult4); - }); - it('bytes', function () { - const _xxx = abi.decodeParameter('bytes', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000'); - assert.equal('df3234', _xxx); - }); - it('uint8[]', function () { - const encodeParameterResult2 = abi.decodeParameter('uint8[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult2); - }); - it('uint32[]', function () { - const encodeParameterResult6 = abi.decodeParameter('uint32[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult6); - }); - it('uint64[]', function () { - const encodeParameterResult8 = abi.decodeParameter('uint64[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult8); - }); - it('uint256[]', function () { - const encodeParameterResult10 = abi.decodeParameter('uint256[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult10); - }); - it('int8[]', function () { - const encodeParameterResult12 = abi.decodeParameter('int8[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult12); - }); - it('int16[]', function () { - const encodeParameterResult14 = abi.decodeParameter('int16[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ '1', '2' ], encodeParameterResult14); - }); - it('int32[]', function () { - const encodeParameterResult16 = abi.decodeParameter('int32[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ 1, 2 ], encodeParameterResult16); - }); - it('int64[]', function () { - const encodeParameterResult18 = abi.decodeParameter('int64[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ 1, 2 ], encodeParameterResult18); - }); - it('int256[]', function () { - const encodeParameterResult20 = abi.decodeParameter('int256[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ 1, 2 ], encodeParameterResult20); - }); - it('bytes1', function () { - const encodeParameterResult21 = abi.decodeParameter('bytes1', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01', encodeParameterResult21); - }); - it('bytes2', function () { - const encodeParameterResult22 = abi.decodeParameter('bytes2', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100', encodeParameterResult22); - }); - it('bytes3', function () { - const encodeParameterResult23 = abi.decodeParameter('bytes3', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('010000', encodeParameterResult23); - }); - it('bytes4', function () { - const encodeParameterResult24 = abi.decodeParameter('bytes4', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01000000', encodeParameterResult24); - }); - it('bytes5', function () { - const encodeParameterResult25 = abi.decodeParameter('bytes5', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000', encodeParameterResult25); - }); - it('bytes6', function () { - const encodeParameterResult26 = abi.decodeParameter('bytes6', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('010000000000', encodeParameterResult26); - }); - it('bytes7', function () { - const encodeParameterResult27 = abi.decodeParameter('bytes7', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01000000000000', encodeParameterResult27); - }); - it('bytes8', function () { - const encodeParameterResult28 = abi.decodeParameter('bytes8', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000', encodeParameterResult28); - }); - it('bytes9', function () { - const encodeParameterResult29 = abi.decodeParameter('bytes9', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('010000000000000000', encodeParameterResult29); - }); - it('bytes10', function () { - const encodeParameterResult30 = abi.decodeParameter('bytes10', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01000000000000000000', encodeParameterResult30); - }); - it('bytes11', function () { - const encodeParameterResult31 = abi.decodeParameter('bytes11', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000', encodeParameterResult31); - }); - it('bytes12', function () { - const encodeParameterResult32 = abi.decodeParameter('bytes12', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('010000000000000000000000', encodeParameterResult32); - }); - it('bytes13', function () { - const encodeParameterResult33 = abi.decodeParameter('bytes13', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01000000000000000000000000', encodeParameterResult33); - }); - it('bytes14', function () { - const encodeParameterResult34 = abi.decodeParameter('bytes14', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000', encodeParameterResult34); - }); - it('bytes15', function () { - const encodeParameterResult35 = abi.decodeParameter('bytes15', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('010000000000000000000000000000', encodeParameterResult35); - }); - it('bytes16', function () { - const encodeParameterResult36 = abi.decodeParameter('bytes16', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01000000000000000000000000000000', encodeParameterResult36); - }); - it('bytes17', function () { - const encodeParameterResult37 = abi.decodeParameter('bytes17', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('0100000000000000000000000000000000', encodeParameterResult37); - }); - it('bytes18', function () { - const encodeParameterResult38 = abi.decodeParameter('bytes18', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('010000000000000000000000000000000000', encodeParameterResult38); - }); - it('bytes19', function () { - const encodeParameterResult39 = abi.decodeParameter('bytes19', '0100000000000000000000000000000000000000000000000000000000000000'); - assert.equal('01000000000000000000000000000000000000', encodeParameterResult39); - }); - it('address[]', function () { - const encodeParameterResult55 = abi.decodeParameter('address[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000'); - assert.deepEqual([ 'vite_00010000000000000000000000000000000000005cce05dbde', 'vite_0002000000000000000000000000000000000000fe64322db1' ], encodeParameterResult55); - }); - it('tokenId[]', function () { - const encodeParameterResult57 = abi.decodeParameter('tokenId[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000'); - assert.deepEqual([ 'tti_01000000000000000000fb5e', 'tti_02000000000000000000199f' ], encodeParameterResult57); - }); - it('gid[]', function () { - const encodeParameterResult56 = abi.decodeParameter('gid[]', '000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000'); - assert.deepEqual([ '01000000000000000000', '02000000000000000000' ], encodeParameterResult56); - }); - it('bytes32[]', function () { - const encodeParameterResult58 = abi.decodeParameter('bytes32[]', '000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000'); - assert.deepEqual([ '0100000000000000000000000000000000000000000000000000000000000000', '0200000000000000000000000000000000000000000000000000000000000000' ], encodeParameterResult58); - }); - it('string', function () { - const encodeParameterResult60 = abi.decodeParameter('string', '0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000'); - assert.equal('foobar', encodeParameterResult60); - }); - it('string 0x02', function () { - const encodeParameterResult60 = abi.decodeParameter('string', '00000000000000000000000000000000000000000000000000000000000000043078303200000000000000000000000000000000000000000000000000000000'); - assert.equal('0x02', encodeParameterResult60); - }); - it('string 02ab', function () { - const encodeParameterResult60 = abi.decodeParameter('string', '00000000000000000000000000000000000000000000000000000000000000043032616200000000000000000000000000000000000000000000000000000000'); - assert.equal('02ab', encodeParameterResult60); - }); - // Not support - it('uint32[2][3][4]', function () { - const encodeParameterResult54 = abi.decodeParameter('uint32[2][3][4]', '000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018'); - assert.deepEqual([[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]], encodeParameterResult54); + describe('encodeParameter', function () { + it('uint256', function () { + const result = abi.encodeParameter('uint256', '2345675643'); + assert.equal('000000000000000000000000000000000000000000000000000000008bd02b7b', result); + }); + it('uint', function () { + const result = abi.encodeParameter('uint', '2345675643'); + assert.equal('000000000000000000000000000000000000000000000000000000008bd02b7b', result); + }); + it('tokenId', function () { + const result = abi.encodeParameter('tokenId', 'tti_5649544520544f4b454e6e40'); + assert.equal('000000000000000000000000000000000000000000005649544520544f4b454e', result); + }); + it('uint8', function () { + const result = abi.encodeParameter('uint8', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('int 2', function () { + const result = abi.encodeParameter('int', '2'); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000002'); + }); + it('int -2', function () { + const result = abi.encodeParameter('int', '-2'); + assert.equal(result, 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + }); + it('int -19999999999999999999999999999999999999999999999999999999999999', function () { + const result = abi.encodeParameter('int', '-19999999999999999999999999999999999999999999999999999999999999'); + assert.equal(result, 'fffffffffffff38dd0f10627f5529bdb2c52d4846810af0ac000000000000001'); + }); + it('bytes', function () { + const result = abi.encodeParameter('bytes', '0xdf3234'); + assert.equal('00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000', result); + }); + it('uint16', function () { + const result = abi.encodeParameter('uint16', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('uint16[]', function () { + const result = abi.encodeParameter('uint16[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('uint16[2]', function () { + const result = abi.encodeParameter('uint16[2]', [ 1, 2 ]); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('uint8[]', function () { + const result = abi.encodeParameter('uint8[]', [ '1', '2' ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('uint32', function () { + const result = abi.encodeParameter('uint32', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('uint32[]', function () { + const result = abi.encodeParameter('uint32[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('uint64', function () { + const result = abi.encodeParameter('uint64', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('uint64[]', function () { + const result = abi.encodeParameter('uint64[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('uint256 -2', function () { + const result = abi.encodeParameter('uint256', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('uint256[]', function () { + const result = abi.encodeParameter('uint256[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('int8', function () { + const result = abi.encodeParameter('int8', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('int8 -2', function () { + const result = abi.encodeParameter('int8', '-2'); + assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', result); + }); + it('int8[]', function () { + const result = abi.encodeParameter('int8[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('int8[] -', function () { + const result = abi.encodeParameter('int8[]', [ -2, -99 ]); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + }); + it('int16', function () { + const result = abi.encodeParameter('int16', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('int16 -2', function () { + const result = abi.encodeParameter('int16', '-2'); + assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', result); + }); + it('int16[]', function () { + const result = abi.encodeParameter('int16[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('int16[] -', function () { + const result = abi.encodeParameter('int16[]', [ -2, -99 ]); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + }); + it('int32', function () { + const result = abi.encodeParameter('int32', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('int32 -2', function () { + const result = abi.encodeParameter('int32', '-2'); + assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', result); + }); + it('int32[]', function () { + const result = abi.encodeParameter('int32[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('int32[] -', function () { + const result = abi.encodeParameter('int16[]', [ -2, -99 ]); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + }); + it('int64', function () { + const result = abi.encodeParameter('int64', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('int64 -2', function () { + const result = abi.encodeParameter('int64', '-2'); + assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', result); + }); + it('int64[]', function () { + const result = abi.encodeParameter('int64[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('int256', function () { + const result = abi.encodeParameter('int256', '2'); + assert.equal('0000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('int256 -2', function () { + const result = abi.encodeParameter('int256', '-2'); + assert.equal('fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', result); + }); + it('int256[]', function () { + const result = abi.encodeParameter('int256[]', [ 1, 2 ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('bytes1', function () { + const result = abi.encodeParameter('bytes1', '0x01'); + assert.equal(result, '0100000000000000000000000000000000000000000000000000000000000000'); + }); + it('bytes2', function () { + const result = abi.encodeParameter('bytes2', '0x0100'); + assert.equal(result, '0100000000000000000000000000000000000000000000000000000000000000'); + }); + it('bytes3', function () { + const result = abi.encodeParameter('bytes3', '0x010000'); + assert.equal(result, '0100000000000000000000000000000000000000000000000000000000000000'); + }); + it('bytes4', function () { + const result = abi.encodeParameter('bytes4', '0x01000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes5', function () { + const result = abi.encodeParameter('bytes5', '0x0100000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes6', function () { + const result = abi.encodeParameter('bytes6', '0x010000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes7', function () { + const result = abi.encodeParameter('bytes7', '0x01000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes8', function () { + const result = abi.encodeParameter('bytes8', '0x0100000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes9', function () { + const result = abi.encodeParameter('bytes9', '0x010000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes10', function () { + const result = abi.encodeParameter('bytes10', '0x01000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes11', function () { + const result = abi.encodeParameter('bytes11', '0x0100000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes12', function () { + const result = abi.encodeParameter('bytes12', '0x010000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes13', function () { + const result = abi.encodeParameter('bytes13', '0x01000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes14', function () { + const result = abi.encodeParameter('bytes14', '0x0100000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes15', function () { + const result = abi.encodeParameter('bytes15', '0x010000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes16', function () { + const result = abi.encodeParameter('bytes16', '0x01000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes17', function () { + const result = abi.encodeParameter('bytes17', '0x0100000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes18', function () { + const result = abi.encodeParameter('bytes18', '0x010000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes19', function () { + const result = abi.encodeParameter('bytes19', '0x01000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes20', function () { + const result = abi.encodeParameter('bytes20', '0x0100000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes21', function () { + const result = abi.encodeParameter('bytes21', '0x010000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes22', function () { + const result = abi.encodeParameter('bytes22', '0x01000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes23', function () { + const result = abi.encodeParameter('bytes23', '0x0100000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes24', function () { + const result = abi.encodeParameter('bytes24', '0x010000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes25', function () { + const result = abi.encodeParameter('bytes25', '0x01000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes26', function () { + const result = abi.encodeParameter('bytes26', '0x0100000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes27', function () { + const result = abi.encodeParameter('bytes27', '0x010000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes28', function () { + const result = abi.encodeParameter('bytes28', '0x01000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes29', function () { + const result = abi.encodeParameter('bytes29', '0x0100000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes30', function () { + const result = abi.encodeParameter('bytes30', '0x010000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes31', function () { + const result = abi.encodeParameter('bytes31', '0x01000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes32', function () { + const result = abi.encodeParameter('bytes32', '0x0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000000000000000000000000000000000', result); + }); + it('address[]', function () { + const result = abi.encodeParameter('address[]', [ 'vite_010000000000000000000000000000000000000063bef3da00', 'vite_0200000000000000000000000000000000000000e4194eedc2' ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000'); + }); + it('address', function () { + const result = abi.encodeParameter('address', 'vite_010000000000000000000000000000000000000063bef3da00'); + assert.equal('0000000000000000000000010000000000000000000000000000000000000000', result); + }); + it('tokenId[]', function () { + const result = abi.encodeParameter('tokenId[]', [ 'tti_01000000000000000000fb5e', 'tti_02000000000000000000199f' ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000'); + }); + it('gid[]', function () { + const result = abi.encodeParameter('gid[]', [ '01000000000000000000', '02000000000000000000' ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000'); + }); + it('gid', function () { + const result = abi.encodeParameter('gid', '01000000000000000000'); + assert.equal('0000000000000000000000000000000000000000000001000000000000000000', result); + }); + it('bool: 0000000000000000000000000000000000000000000000000000000000000001 is true', function () { + const result = abi.encodeParameter('bool', true); + assert.equal('0000000000000000000000000000000000000000000000000000000000000001', result); + }); + it('bool: 0000000000000000000000000000000000000000000000000000000000000000 is false', function () { + const result = abi.encodeParameter('bool', false); + assert.equal('0000000000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes32[]', function () { + const result = abi.encodeParameter('bytes32[]', [ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000000000000000000000000000' ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000'); + }); + it('bytes32[] string', function () { + const result = abi.encodeParameter('bytes32[]', JSON.stringify([ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000000000000000000000000000' ])); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000'); + }); + it('bytes 0X', function () { + const result = abi.encodeParameter('bytes', '0xdf3234'); + assert.equal('00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000', result); + }); + it('bytes', function () { + const result = abi.encodeParameter('bytes', 'df3234'); + assert.equal('00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000', result); + }); + it('string foobar', function () { + const result = abi.encodeParameter('string', 'foobar'); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000'); + }); + it('string 0x02', function () { + const result = abi.encodeParameter('string', '0x02'); + assert.equal(result, '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000043078303200000000000000000000000000000000000000000000000000000000'); + }); + it('string 02ab', function () { + const result = abi.encodeParameter('string', '02ab'); + assert.equal(result, '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000043032616200000000000000000000000000000000000000000000000000000000'); + }); + it('string unicode', function () { + const result = abi.encodeParameter('string', '你好'); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006e4bda0e5a5bd0000000000000000000000000000000000000000000000000000'); + }); + it('string[] 2', function () { + const result = abi.encodeParameter('string[]', [ '02ab', '02ac' ]); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004303261620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043032616300000000000000000000000000000000000000000000000000000000'); + }); + it('string[] 1', function () { + const result = abi.encodeParameter('string[]', ['user']); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047573657200000000000000000000000000000000000000000000000000000000'); + }); + it('string[] 5', function () { + const result = abi.encodeParameter('string[]', [ 'alice', 'alice', 'alice', 'alice', 'alice' ]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + }); + it('string[1]', function () { + const result = abi.encodeParameter('string[1]', ['user']); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047573657200000000000000000000000000000000000000000000000000000000'); + }); + it('string[5]', function () { + const result = abi.encodeParameter('string[5]', [ 'alice', 'alice', 'alice', 'alice', 'alice' ]); + assert.equal(result, '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + }); + it('uint8[2]', function () { + const result = abi.encodeParameter('uint8[2]', [ '1', '2' ]); + assert.equal(result, '00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + }); + it('uint32[2][3][4]', function () { + // Not support + const result = abi.encodeParameter('uint32[2][3][4]', [[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]]); + assert.equal(result, '000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018'); + }); + it('uint32[2][3][4] string', function () { + // Not support + const result = abi.encodeParameter('uint32[2][3][4]', JSON.stringify([[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]])); + assert.equal(result, '000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018'); + }); + it('bytes[][][]', function () { + const result = abi.encodeParameter('bytes[][][]', [[['0x0100000000000000000000000000000000000000000000000000000000000000'], [ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0100000000000000000000000000000000000000000000000000000000000000' ], ['0x0100000000000000000000000000000000000000000000000000000000000000']]]); + assert.equal(result, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000'); + }); }); -}); -describe('encodeParameters', function () { - it('0 abi encodeParameters address[9]', function () { - const result1 = abi.encodeParameters([ - { name: 'jackpot', type: 'uint256' }, - { name: 'offset', type: 'uint8' }, - { name: 'round', type: 'uint64' }, - { name: 'addrs', type: 'address[9]' } - ], [ '500000000000000000', - '2', - '2', [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]]); - - assert.equal(Buffer.from(result1, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); - }); - it('0 abi encodeParameters string address[9]', function () { - const result1 = abi.encodeParameters([ - { name: 'jackpot', type: 'uint256' }, - { name: 'offset', type: 'uint8' }, - { name: 'round', type: 'uint64' }, - { name: 'addrs', type: 'address[9]' } - ], [ '500000000000000000', - '2', - '2', - JSON.stringify([ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]) - ]); - assert.equal(Buffer.from(result1, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); - }); - it('0 abi constructor array', function () { - const encodeParametersResult1 = abi.encodeParameters([ - { 'type': 'uint8[]' }, { 'type': 'bytes' } - ], [[ '34', '43' ], '324567ff' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', encodeParametersResult1); - }); - it('1 abi constructor array', function () { - const encodeParametersResult1 = abi.encodeParameters({ - 'type': 'constructor', - 'inputs': [ - { 'type': 'uint8[]' }, { 'type': 'bytes' } - ] - }, [[ '34', '43' ], '324567ff' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', encodeParametersResult1); - }); - it('1 abi constructor string', function () { - const encodeParametersResult1 = abi.encodeParameters({ - 'type': 'constructor', - 'inputs': [ - { 'type': 'uint8[]' }, { 'type': 'bytes' } - ] - }, JSON.stringify([[ '34', '43' ], '324567ff' ])); - assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', encodeParametersResult1); - }); - it('no inputs', function () { - const encodeParametersResult1 = abi.encodeParameters({ 'type': 'constructor' }); - assert.equal('', encodeParametersResult1); - }); - it('inputs []', function () { - const encodeParametersResult1 = abi.encodeParameters({ 'type': 'constructor', inputs: [] }); - assert.equal('', encodeParametersResult1); - }); - it('multi abi constructor', function () { - const encodeParametersResult12 = abi.encodeParameters([ - { 'type': 'constructor', 'name': 'myMethods', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, - { 'type': 'constructor', 'name': 'myMetod', 'inputs': [{ 'type': 'bytes' }] }, - { 'type': 'constructor', 'name': 'myMethowed', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, - { 'type': 'constructor', 'name': 'myMethossssd', 'inputs': [{ 'type': 'bytes' }] } - ], [[ '34', '43' ], '324567ff' ], 'myMethowed'); - assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', encodeParametersResult12); - }); - it('[ address, uint8[] ]', function () { - const encodeParametersResult2 = abi.encodeParameters([ 'address', 'uint8[]' ], [ 'vite_010000000000000000000000000000000000000063bef3da00', [ 1, 2 ]]); - assert.equal('00000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParametersResult2); - }); - it('[ uint8[], address ]', function () { - const encodeParametersResult3 = abi.encodeParameters([ 'uint8[]', 'address' ], [[ 1, 2 ], 'vite_010000000000000000000000000000000000000063bef3da00' ]); - assert.equal('00000000000000000000000000000000000000000000000000000000000000400000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', encodeParametersResult3); - }); - it('[ tokenId, address ]', function () { - const encodeParametersResult4 = abi.encodeParameters([ 'tokenId', 'address' ], [ 'tti_01000000000000000000fb5e', 'vite_010000000000000000000000000000000000000063bef3da00' ]); - assert.equal('00000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000', encodeParametersResult4); - }); - it('[ string, tokenId, address ]', function () { - const encodeParametersResult5 = abi.encodeParameters([ 'string', 'tokenId', 'address' ], [ '4829482nsdkjskd', 'tti_01000000000000000000fb5e', 'vite_010000000000000000000000000000000000000063bef3da00' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000', encodeParametersResult5); - }); - it('[ string, bytes32[], address ]', function () { - const encodeParametersResult6 = abi.encodeParameters([ 'string', 'bytes32[]', 'address' ], [ '4829482nsdkjskd', [ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000000000000000000000000000' ], 'vite_010000000000000000000000000000000000000063bef3da00' ]); - assert.equal('000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000', encodeParametersResult6); - }); - it('[ int64, int32[], int8 ]', function () { - const encodeParametersResult6 = abi.encodeParameters([ 'int64', 'int32[]', 'int8' ], [ -1, [ -99, -5 ], -9 ]); - assert.equal('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000060fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff70000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb', encodeParametersResult6); + describe('decodeParameter', function () { + it('tokenId', function () { + const result = abi.decodeParameter('tokenId', '000000000000000000000000000000000000000000005649544520544f4b454e'); + assert.equal('tti_5649544520544f4b454e6e40', result); + }); + it('uint8', function () { + const result = abi.decodeParameter('uint8', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('bool: 0000000000000000000000000000000000000000000000000000000000000001 is decode to 1', function () { + const result = abi.decodeParameter('bool', '0000000000000000000000000000000000000000000000000000000000000001'); + assert.equal('1', result); + }); + it('bool: 0000000000000000000000000000000000000000000000000000000000000000 is decode to 0', function () { + const result = abi.decodeParameter('bool', '0000000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0', result); + }); + it('uint16', function () { + const result = abi.decodeParameter('uint16', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('uint32', function () { + const result = abi.decodeParameter('uint32', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('uint64', function () { + const result = abi.decodeParameter('uint64', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('uint256', function () { + const result = abi.decodeParameter('uint256', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('int8', function () { + const result = abi.decodeParameter('int8', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('int8 -2', function () { + const result = abi.decodeParameter('int8', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + assert.equal('-2', result); + }); + it('int8[] -', function () { + const result = abi.decodeParameter('int8[]', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + assert.deepEqual([ -2, -99 ], result); + }); + it('int16', function () { + const result = abi.decodeParameter('int16', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('int16 -2', function () { + const result = abi.decodeParameter('int16', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + assert.equal('-2', result); + }); + it('int16[] -', function () { + const result = abi.decodeParameter('int16[]', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + assert.deepEqual([ -2, -99 ], result); + }); + it('int16[2] -', function () { + const result = abi.decodeParameter('int16[2]', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + assert.deepEqual([ -2, -99 ], result); + }); + it('int32', function () { + const result = abi.decodeParameter('int32', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('int32 -2', function () { + const result = abi.decodeParameter('int32', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + assert.equal('-2', result); + }); + it('int32[] -', function () { + const result = abi.decodeParameter('int16[]', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d'); + assert.deepEqual([ -2, -99 ], result); + }); + it('int64', function () { + const result = abi.decodeParameter('int64', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('int64 -2', function () { + const result = abi.decodeParameter('int64', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + assert.equal(-2, result); + }); + it('int256', function () { + const result = abi.decodeParameter('int256', '0000000000000000000000000000000000000000000000000000000000000002'); + assert.equal('2', result); + }); + it('int256 -2', function () { + const result = abi.decodeParameter('int256', 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + assert.equal(-2, result); + }); + it('uint16[]', function () { + const result = abi.decodeParameter('uint16[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('bytes', function () { + const _xxx = abi.decodeParameter('bytes', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003df32340000000000000000000000000000000000000000000000000000000000'); + assert.equal('df3234', _xxx); + }); + it('uint8[]', function () { + const result = abi.decodeParameter('uint8[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('uint32[]', function () { + const result = abi.decodeParameter('uint32[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('uint64[]', function () { + const result = abi.decodeParameter('uint64[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('uint256[]', function () { + const result = abi.decodeParameter('uint256[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('int8[]', function () { + const result = abi.decodeParameter('int8[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('int16[]', function () { + const result = abi.decodeParameter('int16[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ '1', '2' ], result); + }); + it('int32[]', function () { + const result = abi.decodeParameter('int32[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ 1, 2 ], result); + }); + it('int64[]', function () { + const result = abi.decodeParameter('int64[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ 1, 2 ], result); + }); + it('int256[]', function () { + const result = abi.decodeParameter('int256[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual([ 1, 2 ], result); + }); + it('bytes1', function () { + const result = abi.decodeParameter('bytes1', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01', result); + }); + it('bytes2', function () { + const result = abi.decodeParameter('bytes2', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100', result); + }); + it('bytes3', function () { + const result = abi.decodeParameter('bytes3', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('010000', result); + }); + it('bytes4', function () { + const result = abi.decodeParameter('bytes4', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01000000', result); + }); + it('bytes5', function () { + const result = abi.decodeParameter('bytes5', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000', result); + }); + it('bytes6', function () { + const result = abi.decodeParameter('bytes6', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('010000000000', result); + }); + it('bytes7', function () { + const result = abi.decodeParameter('bytes7', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01000000000000', result); + }); + it('bytes8', function () { + const result = abi.decodeParameter('bytes8', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000', result); + }); + it('bytes9', function () { + const result = abi.decodeParameter('bytes9', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('010000000000000000', result); + }); + it('bytes10', function () { + const result = abi.decodeParameter('bytes10', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01000000000000000000', result); + }); + it('bytes11', function () { + const result = abi.decodeParameter('bytes11', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000', result); + }); + it('bytes12', function () { + const result = abi.decodeParameter('bytes12', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('010000000000000000000000', result); + }); + it('bytes13', function () { + const result = abi.decodeParameter('bytes13', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01000000000000000000000000', result); + }); + it('bytes14', function () { + const result = abi.decodeParameter('bytes14', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000', result); + }); + it('bytes15', function () { + const result = abi.decodeParameter('bytes15', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('010000000000000000000000000000', result); + }); + it('bytes16', function () { + const result = abi.decodeParameter('bytes16', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01000000000000000000000000000000', result); + }); + it('bytes17', function () { + const result = abi.decodeParameter('bytes17', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('0100000000000000000000000000000000', result); + }); + it('bytes18', function () { + const result = abi.decodeParameter('bytes18', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('010000000000000000000000000000000000', result); + }); + it('bytes19', function () { + const result = abi.decodeParameter('bytes19', '0100000000000000000000000000000000000000000000000000000000000000'); + assert.equal('01000000000000000000000000000000000000', result); + }); + it('address[]', function () { + const result = abi.decodeParameter('address[]', '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c50000000000000000000000002aff259c2c1915a49c11fbcb1ae0091a2d6be48d00'); + assert.deepEqual(result, [ 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610', 'vite_2aff259c2c1915a49c11fbcb1ae0091a2d6be48d8bba342fe6' ]); + }); + it('tokenId[]', function () { + const result = abi.decodeParameter('tokenId[]', '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000030831c79099bbe5af0b000000000000000000000000000000000000000000000b16504fe7ab6ba16618c'); + assert.deepEqual(result, [ 'tti_30831c79099bbe5af0b037b1', 'tti_b16504fe7ab6ba16618c3645' ]); + }); + it('gid[]', function () { + const result = abi.decodeParameter('gid[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000'); + assert.deepEqual([ '01000000000000000000', '02000000000000000000' ], result); + }); + it('bytes32[]', function () { + const result = abi.decodeParameter('bytes32[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000'); + assert.deepEqual([ '0100000000000000000000000000000000000000000000000000000000000000', '0200000000000000000000000000000000000000000000000000000000000000' ], result); + }); + it('string', function () { + const result = abi.decodeParameter('string', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000'); + assert.equal('foobar', result); + }); + it('string 0x02', function () { + const result = abi.decodeParameter('string', '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000043078303200000000000000000000000000000000000000000000000000000000'); + assert.equal('0x02', result); + }); + it('string 02ab', function () { + const result = abi.decodeParameter('string', '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000043032616200000000000000000000000000000000000000000000000000000000'); + assert.equal('02ab', result); + }); + it('string unicode', function () { + const result = abi.decodeParameter('string', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006e4bda0e5a5bd0000000000000000000000000000000000000000000000000000'); + assert.equal(result, '你好'); + }); + it('string[]', function () { + const result = abi.decodeParameter('string[]', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047573657200000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, ['user']); + }); + it('string[] -2', function () { + const result = abi.decodeParameter('string[]', '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ 'alice', 'alice', 'alice', 'alice', 'alice' ]); + }); + it('string[] empty', function () { + const result = abi.decodeParameter('string[]', '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, []); + }); + it('string[5]', function () { + const result = abi.decodeParameter('string[5]', '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ 'alice', 'alice', 'alice', 'alice', 'alice' ]); + }); + // Not support + it('uint32[][][]', function () { + const result = abi.decodeParameter('uint32[][][]', '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018'); + assert.deepEqual(result, [[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]]); + }); + it('uint32[2][3][4]', function () { + const result = abi.decodeParameter('uint32[2][3][4]', '000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018'); + assert.deepEqual(result, [[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]]); + }); + it('uint256[2][][3]', function () { + const result = abi.decodeParameter('uint256[2][][3]', + '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual(result, [[[ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]]]); + }); + it('string[][3][]', function () { + const result = abi.decodeParameter('string[][3][]', + '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]]); + }); }); -}); -describe('decodeParameters', function () { - it('case decode parameters addr[]', function () { - const result = abi.decodeParameters([ - { name: 'jackpot', type: 'uint256' }, - { name: 'offset', type: 'uint8' }, - { name: 'round', type: 'uint64' }, - { name: 'addrs', type: 'address[9]' } - ], Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA', 'base64').toString('hex')); + describe('encodeParameters', function () { + it('uint256 uint8 uint64 address[9] type string', function () { + const result = abi.encodeParameters(JSON.stringify([ + { name: 'jackpot', type: 'uint256' }, + { name: 'offset', type: 'uint8' }, + { name: 'round', type: 'uint64' }, + { name: 'addrs', type: 'address[9]' } + ]), [ '500000000000000000', + '2', + '2', [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]]); - assert.deepEqual([ '500000000000000000', - '2', - '2', - [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]], result); - }); - it('case 0', function () { - const result = abi.decodeParameters([ - { 'type': 'uint8[]' }, { 'type': 'bytes' } - ], '000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000'); - assert.deepEqual([[ '34', '43' ], '324567ff' ], result); - }); - it('case 1', function () { - const encodeParametersResult1 = abi.decodeParameters({ - 'type': 'constructor', - 'inputs': [ + assert.equal(Buffer.from(result, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); + }); + it('uint256 uint8 uint64 address[9] type param', function () { + const result = abi.encodeParameters([ + ParamType.from({ name: 'jackpot', type: 'uint256' }), + ParamType.from({ name: 'offset', type: 'uint8' }), + ParamType.from({ name: 'round', type: 'uint64' }), + ParamType.from({ name: 'addrs', type: 'address[9]' }) ], [ '500000000000000000', + '2', + '2', [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]]); + + assert.equal(Buffer.from(result, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); + }); + it('(uint256,uint8,uint64,address[9]) type signature', function () { + const result = abi.encodeParameters('(uint256 jackpot, uint8 offset, uint64 round, address[9] addrs)', [{ + jackpot: '500000000000000000', + offset: '2', + round: '2', + addrs: [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ] + }]); + + assert.equal(Buffer.from(result, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); + }); + it('uint256 uint8 uint64 address[9] type signature', function () { + const result = abi.encodeParameters([ 'uint256 jackpot', 'uint8 offset', 'uint64 round', 'address[9] addrs' ], [ '500000000000000000', + '2', + '2', + JSON.stringify([ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]) + ]); + + assert.equal(Buffer.from(result, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); + }); + it('uint256 uint8 uint64 address[9] type param string', function () { + const result = abi.encodeParameters([ + { name: 'jackpot', type: 'uint256' }, + { name: 'offset', type: 'uint8' }, + { name: 'round', type: 'uint64' }, + { name: 'addrs', type: 'address[9]' } + ], [ '500000000000000000', + '2', + '2', + JSON.stringify([ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]) + ]); + assert.equal(Buffer.from(result, 'hex').toString('base64'), 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA'); + }); + it('uint8[] bytes type', function () { + const result = abi.encodeParameters([ { 'type': 'uint8[]' }, { 'type': 'bytes' } - ] - }, '000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000'); - assert.deepEqual([[ '34', '43' ], '324567ff' ], encodeParametersResult1); - }); - it('case 2', function () { - const encodeParametersResult22 = abi.decodeParameters([ - { 'type': 'function', 'name': 'singl', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, - { - 'type': 'function', - 'name': 'singleParam', + ], [[ '34', '43' ], '324567ff' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes type signature', function () { + const result = abi.encodeParameters([ 'uint8[]', 'bytes' ], [[ '34', '43' ], '324567ff' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes type signature string', function () { + const result = abi.encodeParameters(JSON.stringify([ 'uint8[]', 'bytes' ]), [[ '34', '43' ], '324567ff' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes type string', function () { + const result = abi.encodeParameters(JSON.stringify([ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ]), [[ '34', '43' ], '324567ff' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi string', function () { + const result = abi.encodeParameters(JSON.stringify({ + 'type': 'constructor', 'inputs': [ - { 'name': 'param1', 'type': 'address' }, - { 'name': 'param1', 'type': 'uint8[]' } + { 'type': 'uint8[]' }, { 'type': 'bytes' } ] - } - ], '00000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', 'singleParam'); - assert.deepEqual([ 'vite_00010000000000000000000000000000000000005cce05dbde', [ 1, 2 ]], encodeParametersResult22); - }); - it('case 3', function () { - const encodeParametersResult2 = abi.decodeParameters([ 'address', 'uint8[]' ], '00000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([ 'vite_00010000000000000000000000000000000000005cce05dbde', [ 1, 2 ]], encodeParametersResult2); - }); - it('case 4', function () { - const encodeParametersResult3 = abi.decodeParameters([ 'uint8[]', 'address' ], '00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); - assert.deepEqual([[ 1, 2 ], 'vite_00010000000000000000000000000000000000005cce05dbde' ], encodeParametersResult3); - }); - it('case 5', function () { - const encodeParametersResult4 = abi.decodeParameters([ 'tokenId', 'address' ], '00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000000000'); - assert.deepEqual([ 'tti_01000000000000000000fb5e', 'vite_00010000000000000000000000000000000000005cce05dbde' ], encodeParametersResult4); - }); - it('case 6', function () { - const encodeParametersResult5 = abi.decodeParameters([ 'string', 'tokenId', 'address' ], '000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000'); - assert.deepEqual([ '4829482nsdkjskd', 'tti_01000000000000000000fb5e', 'vite_00010000000000000000000000000000000000005cce05dbde' ], encodeParametersResult5); - }); - it('case 7', function () { - const encodeParametersResult6 = abi.decodeParameters([ 'string', 'bytes32[]', 'address' ], '000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000'); - assert.deepEqual([ '4829482nsdkjskd', [ '0100000000000000000000000000000000000000000000000000000000000000', '0200000000000000000000000000000000000000000000000000000000000000' ], 'vite_00010000000000000000000000000000000000005cce05dbde' ], encodeParametersResult6); - }); - it('case 8', function () { - const encodeParametersResult6 = abi.decodeParameters([ 'int64', 'int32[]', 'int8' ], 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000060fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff70000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb'); - assert.deepEqual([ -1, [ -99, -5 ], -9 ], encodeParametersResult6); + }), [[ '34', '43' ], '324567ff' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi', function () { + const result = abi.encodeParameters([{ + 'type': 'constructor', + 'inputs': [ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ] + }], [[ '34', '43' ], '324567ff' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi param string', function () { + const result = abi.encodeParameters({ + 'type': 'constructor', + 'inputs': [ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ] + }, JSON.stringify([[ '34', '43' ], '324567ff' ])); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi string param string', function () { + const result = abi.encodeParameters(JSON.stringify({ + 'type': 'constructor', + 'inputs': [ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ] + }), JSON.stringify([[ '34', '43' ], '324567ff' ])); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi string array param string', function () { + const result = abi.encodeParameters([JSON.stringify({ + 'type': 'constructor', + 'inputs': [ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ] + })], JSON.stringify([[ '34', '43' ], '324567ff' ])); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('empty type', function () { + const result = abi.encodeParameters({ 'type': 'constructor' }); + assert.equal('', result); + }); + it('empty type 2', function () { + const result = abi.encodeParameters({ 'type': 'constructor', inputs: [] }); + assert.equal('', result); + }); + it('uint8[] bytes abi named', function () { + const result = abi.encodeParameters([ + { 'type': 'constructor', 'name': 'myMethods', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, + { 'type': 'constructor', 'name': 'myMetod', 'inputs': [{ 'type': 'bytes' }] }, + { 'type': 'offchain', 'name': 'myMethowed', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, + { 'type': 'constructor', 'name': 'myMethossssd', 'inputs': [{ 'type': 'bytes' }] } + ], [[ '34', '43' ], '324567ff' ], 'myMethowed'); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi string named callback', function () { + const result = abi.encodeParameters(JSON.stringify([ + { 'type': 'constructor', 'name': 'myMethods', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, + { 'type': 'function', 'name': 'myMetod', 'inputs': [{ 'type': 'bytes' }] }, + { 'type': 'callback', 'name': 'myMethowed', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, + { 'type': 'constructor', 'name': 'myMethossssd', 'inputs': [{ 'type': 'bytes' }] } + ]), [[ '34', '43' ], '324567ff' ], 'myMethowed'); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('uint8[] bytes abi fragment named callback', function () { + const result = abi.encodeParameters([ + Fragment.from({ 'type': 'constructor', 'name': 'myMethods', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }), + Fragment.from({ 'type': 'function', 'name': 'myMetod', 'inputs': [{ 'type': 'bytes' }] }), + Fragment.from({ 'type': 'callback', 'name': 'myMethowed', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }), + Fragment.from({ 'type': 'constructor', 'name': 'myMethossssd', 'inputs': [{ 'type': 'bytes' }] }) + ], [[ '34', '43' ], '324567ff' ], 'myMethowed'); + assert.equal('000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); + it('address uint8[] type', function () { + const result = abi.encodeParameters([ 'address', 'uint8[]' ], [ 'vite_010000000000000000000000000000000000000063bef3da00', [ 1, 2 ]]); + assert.equal('00000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('uint8[] address type', function () { + const result = abi.encodeParameters([ 'uint8[]', 'address' ], [[ 1, 2 ], 'vite_010000000000000000000000000000000000000063bef3da00' ]); + assert.equal('00000000000000000000000000000000000000000000000000000000000000400000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', result); + }); + it('tokenId address type', function () { + const result = abi.encodeParameters([ 'tokenId', 'address' ], [ 'tti_01000000000000000000fb5e', 'vite_010000000000000000000000000000000000000063bef3da00' ]); + assert.equal('00000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000', result); + }); + it('string tokenId address type', function () { + const result = abi.encodeParameters([ 'string', 'tokenId', 'address' ], [ '4829482nsdkjskd', 'tti_01000000000000000000fb5e', 'vite_010000000000000000000000000000000000000063bef3da00' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000', result); + }); + it('string bytes32[] address type', function () { + const result = abi.encodeParameters([ 'string', 'bytes32[]', 'address' ], [ '4829482nsdkjskd', [ '0x0100000000000000000000000000000000000000000000000000000000000000', '0x0200000000000000000000000000000000000000000000000000000000000000' ], 'vite_010000000000000000000000000000000000000063bef3da00' ]); + assert.equal('000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000', result); + }); + it('int64 int32[] int8 type', function () { + const result = abi.encodeParameters([ 'int64', 'int32[]', 'int8' ], [ -1, [ -99, -5 ], -9 ]); + assert.equal('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000060fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff70000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb', result); + }); + it('simple struct abi', function () { + const result = abi.encodeParameters([{'name': 'getBet', 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'} ], 'internalType': 'struct Hello.BetLimit', 'name': '', 'type': 'tuple'}], 'stateMutability': 'pure', 'type': 'function'}], + [{ lowerLimit: 1, upperLimit: 1, tipPer: 1 }]); + assert.deepEqual('000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001', result); + }); + it('complex struct abi', function () { + const result = abi.encodeParameters([{'name': 'getBet', 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'components': [ {'internalType': 'string', 'name': 'name', 'type': 'string'}, {'internalType': 'address', 'name': 'addr', 'type': 'address'} ], 'internalType': 'struct Hello.User[]', 'name': 'users', 'type': 'tuple[]'}, {'internalType': 'string[][3][]', 'name': 'result', 'type': 'string[][3][]'} ], 'internalType': 'struct Hello.BetLimit', 'name': '', 'type': 'tuple'}], 'stateMutability': 'pure', 'type': 'function'}], + [{ lowerLimit: 1, upperLimit: 2, tipPer: 3, users: [ {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' }, {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' } ], result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]]}]); + assert.deepEqual('000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000', result); + }); }); - it('case 9: decode for bool', function () { - const types = [ - { name: 'success', type: 'bool' }, - { name: 'successStr', type: 'string' } - ]; - const result = abi.decodeParameters(types, Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEdHJ1ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', 'base64').toString('hex')); - assert.deepEqual([ '1', 'true' ], result); + describe('decodeParameters', function () { + it('uint256 uint8 uint64 address[9] type', function () { + const result = abi.decodeParameters([ + { name: 'jackpot', type: 'uint256' }, + { name: 'offset', type: 'uint8' }, + { name: 'round', type: 'uint64' }, + { name: 'addrs', type: 'address[9]' } + ], Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvBbWdOyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIAAAAAAAAAAAAAAAAv46lxUd56V7XoxYpfMtYC7+TccgAAAAAAAAAAAAAAAC/jqXFR3npXtejFil8y1gLv5NxyAAAAAAAAAAAAAAAAL+OpcVHeele16MWKXzLWAu/k3HIA', 'base64').toString('hex')); + assert.deepEqual(result, [ '500000000000000000', + '2', + '2', + [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ]]); + }); + it('uint8[] bytes type', function () { + const result = abi.decodeParameters([ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ], '000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [[ '34', '43' ], '324567ff' ]); + }); + it('uint8[] bytes abi', function () { + const result = abi.decodeParameters({ + 'type': 'constructor', + 'inputs': [ + { 'type': 'uint8[]' }, { 'type': 'bytes' } + ] + }, '000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [[ '34', '43' ], '324567ff' ]); + }); + it('address uint8[] abi named', function () { + const result = abi.decodeParameters([ + { 'type': 'function', 'name': 'singl', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, + { + 'type': 'function', + 'name': 'singleParam', + 'inputs': [ + { 'name': 'param1', 'type': 'address' }, + { 'name': 'param2', 'type': 'uint8[]' } + ] + } + ], '0000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c5000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', 'singleParam'); + assert.deepEqual(result, [ 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610', [ 1, 2 ]]); + }); + it('address uint8[] type', function () { + const result = abi.decodeParameters([ 'address', 'uint8[]' ], '0000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c5000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual(result, [ 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610', [ 1, 2 ]]); + }); + it('uint8[] address type', function () { + const result = abi.decodeParameters([ 'uint8[]', 'address' ], '00000000000000000000000000000000000000000000000000000000000000400000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c500000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002'); + assert.deepEqual(result, [[ 1, 2 ], 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610' ]); + }); + it('tokenId address type', function () { + const result = abi.decodeParameters([ 'tokenId', 'address' ], '0000000000000000000000000000000000000000000030831c79099bbe5af0b00000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c500'); + assert.deepEqual(result, [ 'tti_30831c79099bbe5af0b037b1', 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610' ]); + }); + it('string tokenId address type', function () { + const result = abi.decodeParameters([ 'string', 'tokenId', 'address' ], '00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000030831c79099bbe5af0b00000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c500000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000'); + assert.deepEqual(result, [ '4829482nsdkjskd', 'tti_30831c79099bbe5af0b037b1', 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610' ]); + }); + it('string byte32[] address type', function () { + const result = abi.decodeParameters([ 'string', 'bytes32[]', 'address' ], '000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000644c3f9a40c26c443bed3a87a10e4f639a5881c500000000000000000000000000000000000000000000000000000000000000000f343832393438326e73646b6a736b640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ '4829482nsdkjskd', [ '0100000000000000000000000000000000000000000000000000000000000000', '0200000000000000000000000000000000000000000000000000000000000000' ], 'vite_644c3f9a40c26c443bed3a87a10e4f639a5881c5f334859610' ]); + }); + it('int64 int32[] int8 type', function () { + const result = abi.decodeParameters([ 'int64', 'int32[]', 'int8' ], 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000060fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff70000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb'); + assert.deepEqual(result, [ -1, [ -99, -5 ], -9 ]); + }); + it('empty type', function () { + const result = abi.decodeParameters({ 'type': 'constructor' }, ''); + assert.deepEqual(result, []); + }); + it('empty type 2', function () { + const result = abi.decodeParameters({ 'type': 'constructor', inputs: [] }, ''); + assert.deepEqual(result, []); + }); + it('bool string type', function () { + const types = [ + { name: 'success', type: 'bool' }, + { name: 'successStr', type: 'string' } + ]; + const result = abi.decodeParameters(types, Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEdHJ1ZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', 'base64').toString('hex')); + assert.deepEqual(result, [ '1', 'true' ]); + assert.deepEqual(result, [ true, 'true' ]); - const result2 = abi.decodeParameters(types, Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZmFsc2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', 'base64').toString('hex')); - assert.deepEqual([ '0', 'false' ], result2); + const result2 = abi.decodeParameters(types, Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZmFsc2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', 'base64').toString('hex')); + assert.deepEqual(result2, [ '0', 'false' ]); + assert.deepEqual(result2, [ false, 'false' ]); + }); + it('simple struct abi', function () { + const result = abi.decodeParameters([{'name': 'getBet', 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'} ], 'internalType': 'struct Hello.BetLimit', 'name': '', 'type': 'tuple'}], 'stateMutability': 'pure', 'type': 'function'}], + '000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001'); + assert.deepEqual(result, [{ lowerLimit: 1, upperLimit: 1, tipPer: 1 }]); + }); + it('complex struct abi', function () { + const result = abi.decodeParameters([{'name': 'getBet', 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'components': [ {'internalType': 'string', 'name': 'name', 'type': 'string'}, {'internalType': 'address', 'name': 'addr', 'type': 'address'} ], 'internalType': 'struct Hello.User[]', 'name': 'users', 'type': 'tuple[]'}, {'internalType': 'string[][3][]', 'name': 'result', 'type': 'string[][3][]'} ], 'internalType': 'struct Hello.BetLimit', 'name': 'bet', 'type': 'tuple'}], 'stateMutability': 'pure', 'type': 'function'}], + '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [{ lowerLimit: 1, upperLimit: 2, tipPer: 3, users: [ {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' }, {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' } ], result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]]}]); + }); + it('uint256[][] string[5][] uint256[3][5] abi', function () { + const result = abi.decodeParameters({'inputs': [ {'internalType': 'uint256[][]', 'name': 'input1', 'type': 'uint256[][]'}, {'internalType': 'string[5][]', 'name': 'input2', 'type': 'string[5][]'}, {'internalType': 'uint256[3][5]', 'name': 'input3', 'type': 'uint256[3][5]'} ], 'name': 'compoundArr2DR3WithInput', 'outputs': [ {'internalType': 'uint256[][]', 'name': '', 'type': 'uint256[][]'}, {'internalType': 'string[5][]', 'name': '', 'type': 'string[5][]'}, {'internalType': 'uint256[3][5]', 'name': '', 'type': 'uint256[3][5]'} ], 'stateMutability': 'pure', 'type': 'function'}, + '00000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000004600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c69636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c69636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c69636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c69636500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [[[1], [ 1, 2 ], [ 1, 2, 3 ], [ 1, 2, 3, 4 ], [ 1, 2, 3, 4, 5 ]], [[ 'alice', 'alice', 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice', 'alice', 'alice' ]], [[ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ]]]); + }); }); -}); -describe('encodeFunctionSignature', function () { - it('case 1', function () { - const encodeMethodResult1 = abi.encodeFunctionSignature({ 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }); - assert.equal('053f71a4', encodeMethodResult1); - }); - it('case 2', function () { - const encodeMethodResult2 = abi.encodeFunctionSignature({ 'type': 'function', 'name': 'twoParams', 'inputs': [ { 'name': 'param1', 'type': 'tokenId' }, { 'name': 'param2', 'type': 'uint256[2]' } ] }); - assert.equal('41bdf4f6', encodeMethodResult2); - }); - it('case 3', function () { - const encodeMethodResult3 = abi.encodeFunctionSignature([{ 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }]); - assert.equal('053f71a4', encodeMethodResult3); - }); - it('case 4', function () { - const encodeMethodResult4 = abi.encodeFunctionSignature([ - { 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, - { 'type': 'function', 'name': 'singl', 'inputs': [{ 'name': 'param1', 'type': 'address' }] } - ], 'singleParam'); - assert.equal('053f71a4', encodeMethodResult4); - }); - it('case 5', function () { - const encodeMethodResult5 = abi.encodeFunctionSignature('singleParam(address)'); - assert.equal('053f71a4', encodeMethodResult5); - }); - it('case 6', function () { - const encodeMethodResult1 = abi.encodeFunctionSignature({ 'type': 'function', 'name': 'noParam' }); - assert.equal('e3cb7377', encodeMethodResult1); + describe('encodeFunctionSignature', function () { + it('address', function () { + const result = abi.encodeFunctionSignature([{ 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }], 'singleParam'); + assert.equal('053f71a4', result); + }); + it('tokenId uint256[2]', function () { + const result = abi.encodeFunctionSignature({ 'type': 'function', 'name': 'twoParams', 'inputs': [ { 'name': 'param1', 'type': 'tokenId' }, { 'name': 'param2', 'type': 'uint256[2]' } ] }); + assert.equal('41bdf4f6', result); + }); + it('address sighash', function () { + const result = abi.encodeFunctionSignature([ { 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, + { 'type': 'function', 'name': 'twoParams', 'inputs': [ { 'name': 'param1', 'type': 'tokenId' }, { 'name': 'param2', 'type': 'uint256[2]' } ] } ], '053f71a4'); + assert.equal('053f71a4', result); + }); + it('address named', function () { + const result = abi.encodeFunctionSignature([ + { 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, + { 'type': 'function', 'name': 'singl', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, + { 'type': 'function', 'name': 'singl', 'inputs': [{ 'name': 'param1', 'type': 'address' }] } + ], 'singleParam'); + assert.equal('053f71a4', result); + }); + it('blake2bHex', function () { + const result = blake2bHex('singleParam(address)', null, 32).slice(0, 8); + assert.equal('053f71a4', result); + }); + it('no param', function () { + const result = abi.encodeFunctionSignature({ 'type': 'function', 'name': 'noParam' }); + assert.equal('e3cb7377', result); + }); + it('address signature named', function () { + const result = abi.encodeFunctionSignature([ + { 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }, + { 'type': 'function', 'name': 'singl', 'inputs': [{ 'name': 'param1', 'type': 'address' }] } + ], 'singleParam(address)'); + assert.equal('053f71a4', result); + }); }); -}); -describe('encodeLogSignature', function () { - it('case 1', function () { - const encodeLogSignatureResult1 = abi.encodeLogSignature({ - 'type': 'event', - 'name': 'balance', - 'inputs': [{ 'name': 'in', 'type': 'uint256' }] - }); - assert.equal('8a3390b86e28f274e3a88354b3b83cf0f8780a1f0975f629966bd2a2d38eb188', encodeLogSignatureResult1); - }); - it('case 2', function () { - const encodeLogSignatureResult2 = abi.encodeLogSignature({ 'type': 'event', 'name': 'check', 'inputs': [ { 'name': 't', 'type': 'address' }, { 'name': 'b', 'type': 'uint256' } ] }); - assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', encodeLogSignatureResult2); - }); - it('case 3', function () { - const encodeLogSignatureResult22 = abi.encodeLogSignature([ - { 'type': 'event', 'name': 'heck', 'inputs': [{ 'name': 't', 'type': 'address' }] }, - { 'type': 'event', 'name': 'check', 'inputs': [ { 'name': 't', 'type': 'address' }, { 'name': 'b', 'type': 'uint256' } ] }, - { 'type': 'event', 'name': 'eck', 'inputs': [] } - ], 'check'); - assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', encodeLogSignatureResult22); + describe('encodeLogSignature', function () { + it('uint256', function () { + const result = abi.encodeLogSignature({ + 'type': 'event', + 'name': 'balance', + 'inputs': [{ 'name': 'in', 'type': 'uint256' }] + }); + assert.equal('8a3390b86e28f274e3a88354b3b83cf0f8780a1f0975f629966bd2a2d38eb188', result); + }); + it('uint256 signature', function () { + const result = abi.encodeLogSignature(['event balance(uint256 in)']); + assert.equal('8a3390b86e28f274e3a88354b3b83cf0f8780a1f0975f629966bd2a2d38eb188', result); + }); + it('address uint256', function () { + const result = abi.encodeLogSignature({ 'type': 'event', 'name': 'check', 'inputs': [ { 'name': 't', 'type': 'address' }, { 'name': 'b', 'type': 'uint256' } ] }); + assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', result); + }); + it('address uint256 named sighash', function () { + const result = abi.encodeLogSignature({ 'type': 'event', 'name': 'check', 'inputs': [ { 'name': 't', 'type': 'address' }, { 'name': 'b', 'type': 'uint256' } ] }, + '17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220'); + assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', result); + }); + it('address uint256 named signature', function () { + const result = abi.encodeLogSignature({ 'type': 'event', 'name': 'check', 'inputs': [ { 'name': 't', 'type': 'address' }, { 'name': 'b', 'type': 'uint256' } ] }, + 'check(address,uint256)'); + assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', result); + }); + it('address uint256 named', function () { + const result = abi.encodeLogSignature([ + { 'type': 'event', 'name': 'heck', 'inputs': [{ 'name': 't', 'type': 'address' }] }, + { 'type': 'event', 'name': 'check', 'inputs': [ { 'name': 't', 'type': 'address' }, { 'name': 'b', 'type': 'uint256' } ] }, + { 'type': 'event', 'name': 'eck', 'inputs': [] } + ], 'check'); + assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', result); + }); + it('address uint256 signature named', function () { + const result = abi.encodeLogSignature([ 'event heck(address t)', 'event check(address t, uint256 b)', 'event eck()' ], 'check'); + assert.equal('17c53855485cba60b5dea781a996394bb9d3b44bc8932b3adf79ac70e908b220', result); + }); }); -}); -describe('decodeLog', function () { - it('only one non-indexed param', function () { - const decodeResult = abi.decodeLog({'anonymous': false, 'inputs': [{'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'}], 'name': 'Event1', 'type': 'event'}, - '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', - ['30e00162ff22a0d2aaa98f7013fc6dcb0bfae6a56ed30e35c5ea19326211a1a9'], - 'Event1'); + describe('decodeLog', function () { + it('one non-indexed param', function () { + const result = abi.decodeLog({'anonymous': false, 'inputs': [{'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'}], 'name': 'Event1', 'type': 'event'}, + '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + ['30e00162ff22a0d2aaa98f7013fc6dcb0bfae6a56ed30e35c5ea19326211a1a9'], + 'Event1'); - assert.deepEqual(decodeResult, { - '0': 'hello world', - data: 'hello world' + assert.deepEqual(result, { + '0': 'hello world', + data: 'hello world' + }); }); - }); + it('two non-indexed params', function () { + const result = abi.decodeLog({ + 'anonymous': false, + 'inputs': [ + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'} + ], + 'name': 'Event2', + 'type': 'event' + }, + '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + ['89dd96aeda3674789db84f190f6ddc0fe541b74ad26f0175aec573e0232e0fd5']); - it('two non-indexed params', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': false, - 'inputs': [ - {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, - {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'} - ], - 'name': 'Event2', - 'type': 'event' - }, - '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', - ['89dd96aeda3674789db84f190f6ddc0fe541b74ad26f0175aec573e0232e0fd5']); + assert.deepEqual(result, { + '0': '123', + '1': 'hello world', + i: '123', + s: 'hello world' + }); + }); + it('one indexed and two non-indexed params', function () { + const result = abi.decodeLog({ + 'anonymous': false, + 'inputs': [ + {'indexed': true, 'internalType': 'uint256', 'name': 't', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'} + ], + 'name': 'Event3', + 'type': 'event' + }, + '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + [ + 'ff75de284617dcb8120f62e0ab99092112d2fa831082b3cb4d6703a07a757a88', + '0000000000000000000000000000000000000000000000000000000000000001' + ]); - assert.deepEqual(decodeResult, { - '0': '123', - '1': 'hello world', - i: '123', - s: 'hello world' + assert.deepEqual(result, { + '0': '1', + '1': '123', + '2': 'hello world', + t: '1', + i: '123', + s: 'hello world' + }); }); - }); + it('two indexed and two non-indexed params', function () { + const result = abi.decodeLog({ + 'anonymous': false, + 'inputs': [ + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': true, 'internalType': 'uint256', 'name': 't1', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'}, + {'indexed': true, 'internalType': 'string', 'name': 't2', 'type': 'string'} + ], + 'name': 'Event4', + 'type': 'event' + }, + '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + [ + 'b787fae491b126a61d9e5c4f03e16463e6f1f985d0682dd2d1a844331b539e9c', + '0000000000000000000000000000000000000000000000000000000000000001', + 'afd7f7d4710d29fbfc539d707a42ff910cd4d41a4c9eae3356180f074e8c3da1' + ]); - it('one indexed and two non-indexed params', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': false, - 'inputs': [ - {'indexed': true, 'internalType': 'uint256', 'name': 't', 'type': 'uint256'}, - {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, - {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'} - ], - 'name': 'Event3', - 'type': 'event' - }, - '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', - [ - 'ff75de284617dcb8120f62e0ab99092112d2fa831082b3cb4d6703a07a757a88', - '0000000000000000000000000000000000000000000000000000000000000001' - ]); + assert.deepEqual(result, { + '0': '123', + '1': '1', + '2': 'hello world', + '3': 'afd7f7d4710d29fbfc539d707a42ff910cd4d41a4c9eae3356180f074e8c3da1', + i: '123', + t1: '1', + s: 'hello world', + t2: 'afd7f7d4710d29fbfc539d707a42ff910cd4d41a4c9eae3356180f074e8c3da1' + }); + }); + it('anonymous event', function () { + const result = abi.decodeLog({ + 'anonymous': true, + 'inputs': [ + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'} + ], + 'name': 'AnonymousEvent', + 'type': 'event' + }, + '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + null); - assert.deepEqual(decodeResult, { - '0': '1', - '1': '123', - '2': 'hello world', - t: '1', - i: '123', - s: 'hello world' + assert.deepEqual(result, { + '0': '123', + '1': 'hello world', + i: '123', + data: 'hello world' + }); }); - }); + it('anonymous event with indexed params', function () { + const result = abi.decodeLog({ + 'anonymous': true, + 'inputs': [ + {'indexed': true, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'} + ], + 'name': 'AnonymousEvent', + 'type': 'event' + }, + '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + ['000000000000000000000000000000000000000000000000000000000000007b']); - it('two indexed and two non-indexed params', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': false, - 'inputs': [ - {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, - {'indexed': true, 'internalType': 'uint256', 'name': 't1', 'type': 'uint256'}, - {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'}, - {'indexed': true, 'internalType': 'string', 'name': 't2', 'type': 'string'} - ], - 'name': 'Event4', - 'type': 'event' - }, - '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', - [ - 'b787fae491b126a61d9e5c4f03e16463e6f1f985d0682dd2d1a844331b539e9c', - '0000000000000000000000000000000000000000000000000000000000000001', - 'afd7f7d4710d29fbfc539d707a42ff910cd4d41a4c9eae3356180f074e8c3da1' - ]); + assert.deepEqual(result, { + '0': '123', + '1': 'hello world', + i: '123', + data: 'hello world' + }); + }); + it('only one non-indexed token id', function () { + const result = abi.decodeLog({ + 'anonymous': false, + 'inputs': [ + {'indexed': false, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} + ], + 'name': 'TestEvent', + 'type': 'event' + }, + '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a', + ['8b5075daac7054843301efa983d65ebb0a2ab0943c4464c5d90116bac31b558e']); - assert.deepEqual(decodeResult, { - '0': '123', - '1': '1', - '2': 'hello world', - '3': 'afd7f7d4710d29fbfc539d707a42ff910cd4d41a4c9eae3356180f074e8c3da1', - i: '123', - t1: '1', - s: 'hello world', - t2: 'afd7f7d4710d29fbfc539d707a42ff910cd4d41a4c9eae3356180f074e8c3da1' + assert.deepEqual(result, { + '0': 'tti_b0de22e5d54c92c43c3a9e54', + tti: 'tti_b0de22e5d54c92c43c3a9e54' + }); }); - }); + it('one indexed token id', function () { + const result = abi.decodeLog({ + 'anonymous': false, + 'inputs': [ + {'indexed': true, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} + ], + 'name': 'TestEvent', + 'type': 'event' + }, + '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a', + [ + '8b5075daac7054843301efa983d65ebb0a2ab0943c4464c5d90116bac31b558e', + '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a' ]); - it('anonymous event', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': true, - 'inputs': [ - {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, - {'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'} - ], - 'name': 'AnonymousEvent', - 'type': 'event' - }, - '000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', - null); + assert.deepEqual(result, { + '0': 'tti_b0de22e5d54c92c43c3a9e54', + tti: 'tti_b0de22e5d54c92c43c3a9e54' + }); + }); + it('indexed struct', function () { + const result = abi.decodeLog([{'anonymous': false, 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'internalType': 'string[][3][]', 'name': 'result', 'type': 'string[][3][]'} ], 'indexed': true, 'internalType': 'struct Hello.BetLimit', 'name': 'bet', 'type': 'tuple'}], 'name': 'DeployedBet', 'type': 'event'}], + '', + [ + '308561ee2a3c3ea5df3689e7131e0ca7006467c81f664528bd01c96f3783a6ef', + '91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0' ], 'DeployedBet'); + assert.deepEqual(result, { + '0': blake2bHex(Buffer.concat([ arrayify(abi.encodeParameter('uint256', 1)), + arrayify(abi.encodeParameter('uint256', 2)), + arrayify(abi.encodeParameter('uint256', 3)), + arrayify(rightPadZero(Buffer.from('alice'), 32)), + arrayify(rightPadZero(Buffer.from('alice'), 32)), + arrayify(rightPadZero(Buffer.from('alice'), 32)), + arrayify(rightPadZero(Buffer.from('alice'), 32)), + arrayify(rightPadZero(Buffer.from('alice'), 32)), + arrayify(rightPadZero(Buffer.from('alice'), 32)) + ]), null, 32), + bet: blake2bHex(arrayify('0000000000000000000000000000000000000000000000000000000000000001' + + '0000000000000000000000000000000000000000000000000000000000000002' + + '0000000000000000000000000000000000000000000000000000000000000003' + + '616c696365000000000000000000000000000000000000000000000000000000' + + '616c696365000000000000000000000000000000000000000000000000000000' + + '616c696365000000000000000000000000000000000000000000000000000000' + + '616c696365000000000000000000000000000000000000000000000000000000' + + '616c696365000000000000000000000000000000000000000000000000000000' + + '616c696365000000000000000000000000000000000000000000000000000000'), null, 32) + }); + }); + it('indexed struct signature', function () { + const result = abi.decodeLog(['event DeployedBet(tuple(uint256 lowerLimit, uint256 upperLimit, uint256 tipPer, string[][3][] result) indexed bet)'], + '', + [ + '308561ee2a3c3ea5df3689e7131e0ca7006467c81f664528bd01c96f3783a6ef', + '91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0' ], 'DeployedBet'); + assert.deepEqual(result, { + '0': '91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0', + bet: '91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0' + }); + }); + it('indexed struct(string)', function () { + const result = abi.decodeLog([{'anonymous': false, 'inputs': [{'components': [{'internalType': 'string', 'name': 'name', 'type': 'string'}], 'indexed': true, 'internalType': 'struct Hello.User', 'name': 'user', 'type': 'tuple'}], 'name': 'DeployedUser', 'type': 'event'}], + '', + [ + 'c295e9f5dcf18a3023ea961e6fd722b7253c708b3ab4401955ef7e38ee0cae3b', + '9d8f93d903f59e47e183534619576172ebbddaeb00eb47b26ee5e3d4902a626f' ]); + assert.deepEqual(result, { + '0': blake2bHex(arrayify(rightPadZero(Buffer.from('name'), 32)), null, 32), + user: blake2bHex(arrayify('6e616d6500000000000000000000000000000000000000000000000000000000'), null, 32) + }); + }); + it('indexed string address', function () { + const result = abi.decodeLog([{'anonymous': false, 'inputs': [ {'indexed': true, 'internalType': 'string', 'name': 'name', 'type': 'string'}, {'indexed': true, 'internalType': 'address', 'name': 'addr', 'type': 'address'} ], 'name': 'Deployed', 'type': 'event'}], + '', + [ + 'd9ca50fd94453788f40ba2ea6ace8170619a54ce0ffb0839993bf9342ca13b54', + '3adaf70d6a60eba6aaa6a1884c382ae32b223557ccaa2f3fcab6aec6c2fca21f', + '00000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a00' ], 'Deployed'); - assert.deepEqual(decodeResult, { - '0': '123', - '1': 'hello world', - i: '123', - data: 'hello world' + assert.deepEqual(result, { + '0': blake2bHex('name', null, 32), + '1': 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6', + name: blake2bHex(Buffer.from('name'), null, 32), + addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' + }); + }); + it('indexed struct(string,address)', function () { + const result = abi.decodeLog([{'anonymous': false, 'inputs': [{'components': [ {'internalType': 'string', 'name': 'name', 'type': 'string'}, {'internalType': 'address', 'name': 'addr', 'type': 'address'} ], 'indexed': true, 'internalType': 'struct Hello.User', 'name': 'user', 'type': 'tuple'}], 'name': 'DeployedUser', 'type': 'event'}], + '', + [ + 'a726de6a27282e9f2fd40ef5acb830570c4692fb93330688f812d9de29c4a4de', + 'd24057e115ec2936b95a95de18f6272a7ff18a572a393f3fecb9c517e322be95' ], 'DeployedUser'); + assert.deepEqual(result, { + '0': blake2bHex(Buffer.concat([ arrayify(rightPadZero(Buffer.from('name'), 32)), + arrayify(abi.encodeParameter('address', 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6')) ]), null, 32), + user: 'd24057e115ec2936b95a95de18f6272a7ff18a572a393f3fecb9c517e322be95' + }); + }); + it('indexed string[]', function () { + const result = abi.decodeLog([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'string[]', 'name': 'user', 'type': 'string[]'}], 'name': 'DeployedUser', 'type': 'event'}], + '', + [ + '77eaa9d8538de877bc481f8d5cc7ed2d439983f13f0f0e1cb77ddf54b79a864d', + '9fdc9b04e2582fb90d298fa3a2f92d1f88fd80f130456a48ca49d330d6fb320a' ], 'DeployedUser'); + assert.deepEqual(result, { + '0': blake2bHex(Buffer.concat([ arrayify(rightPadZero(Buffer.from('alice'), 32)), + arrayify(rightPadZero(Buffer.from('alice'), 32)) ]), null, 32), + user: blake2bHex(arrayify('616c696365000000000000000000000000000000000000000000000000000000' + + '616c696365000000000000000000000000000000000000000000000000000000'), null, 32) + }); + }); + it('reIssue', function () { + const result = abi.decodeLog([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'tokenId', 'name': 'tokenId', 'type': 'tokenId'}], 'name': 'reIssue', 'type': 'event'}], + '', + [ + '0d21bc90666d2ba979f104f8fbd1ee0331d8e11da2893ffedbd375557e2d453d', + '000000000000000000000000000000000000000000000a1a6be7e19ed593dbb6' ], 'reIssue'); + assert.deepEqual(result, { + '0': 'tti_0a1a6be7e19ed593dbb664c8', + tokenId: 'tti_0a1a6be7e19ed593dbb664c8' + }); }); }); - it('anonymous event with indexed params', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': true, - 'inputs': [ - {'indexed': true, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, - {'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'} - ], - 'name': 'AnonymousEvent', - 'type': 'event' - }, - '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', - ['000000000000000000000000000000000000000000000000000000000000007b']); + describe('encodeFunctionCall', function () { + it('uint256 string', function () { + const result = abi.encodeFunctionCall({ + name: 'myMethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + }, [ '2345675643', 'Hello!%' ]); + assert.equal('96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', result); + }); + it('uint256 string named', function () { + const result = abi.encodeFunctionCall([ { + name: 'myMethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + }, { + name: 'myethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + } ], [ '2345675643', 'Hello!%' ], 'myMethod'); + assert.equal('96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', result); + }); + it('int16[]', function () { + const result = abi.encodeFunctionCall({ 'constant': false, 'inputs': [{ 'name': 'proposal', 'type': 'int16[]' }], 'name': 'vote', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, [[ -2, -2 ]]); + assert.equal('aa941d3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', result); + }); + it('int16[] -9999', function () { + const result = abi.encodeFunctionCall({ 'constant': false, 'inputs': [{ 'name': 'proposal', 'type': 'int16[]' }], 'name': 'vote', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, [[ -2, -9999 ]]); + assert.equal('aa941d3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f1', result); + }); + it('int16[] signature', function () { + const result = abi.encodeFunctionCall([ 'function vote(int16[] proposal)', + 'receive()' ], [[ -2, -9999 ]], 'vote'); + assert.equal('aa941d3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f1', result); + }); + it('CreateNewInviter', function () { + const result = abi.encodeFunctionCall({ 'type': 'function', 'name': 'CreateNewInviter', 'inputs': [] }, []); + assert.equal('d8088efc', result); + }); + }); - assert.deepEqual(decodeResult, { - '0': '123', - '1': 'hello world', - i: '123', - data: 'hello world' + describe('decodeFunctionCall', function () { + it('uint256 string', function () { + const result = abi.decodeFunctionCall({ + name: 'myMethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + }, '96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ '2345675643', 'Hello!%' ]); + }); + it('uint256 string signature array', function () { + const result = abi.decodeFunctionCall(['function myMethod(uint256 myNumber, string myString)'], '96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ '2345675643', 'Hello!%' ]); + }); + it('uint256 string signature', function () { + const result = abi.decodeFunctionCall('function myMethod(uint256 myNumber, string myString)', '96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ '2345675643', 'Hello!%' ]); + }); + it('uint256 string json', function () { + const result = abi.decodeFunctionCall(JSON.stringify({ + name: 'myMethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + }), '96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [ '2345675643', 'Hello!%' ]); + }); + it('uint256 string signature named', function () { + const result = abi.decodeFunctionCall([ 'function myMethod(uint256 myNumber, string myString)', 'function myethod(uint256 myNumber, string myString)' ] + , '96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', 'myMethod'); + assert.deepEqual(result, [ '2345675643', 'Hello!%' ]); + }); + it('uint256 string named', function () { + const result = abi.decodeFunctionCall([ { + name: 'myMethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + }, { + name: 'myethod', + type: 'function', + inputs: [ { + type: 'uint256', + name: 'myNumber' + }, { + type: 'string', + name: 'myString' + } ] + } ], '96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', 'myMethod'); + assert.deepEqual(result, [ '2345675643', 'Hello!%' ]); + }); + it('int16[]', function () { + const result = abi.decodeFunctionCall({ 'constant': false, 'inputs': [{ 'name': 'proposal', 'type': 'int16[]' }], 'name': 'vote', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, 'aa941d3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe'); + assert.deepEqual(result, [[ -2, -2 ]]); + }); + it('StakeForQuotaWithCallback', function () { + const result = abi.decodeFunctionCall({ 'constant': false, 'inputs': [ { 'name': 'beneficiary', 'type': 'address' }, { 'name': 'stakeHeight', 'type': 'uint64' } ], 'name': 'StakeForQuotaWithCallback', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, Buffer.from('a+10LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnjQA=', 'base64').toString('hex')); + assert.deepEqual(result, [ 'vite_0000000000000000000000000000000000000006e82b8ba657', 2592000 ]); + }); + it('StakeForQuotaWithCallback named callback', function () { + const result = abi.decodeFunctionCall([ { 'constant': false, 'inputs': [{ 'name': 'beneficiary', 'type': 'address' }], 'name': 'StakeForQuota', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, + {'type': 'callback', 'name': 'StakeForQuotaWithCallback', 'inputs': [ {'name': 'id', 'type': 'bytes32'}, {'name': 'success', 'type': 'bool'} ]} ], Buffer.from('VLTtU9GkzOKAn9+1FlLaZrpXGM8380QdWjmpn5qxSyCSBqssAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=', 'base64').toString('hex'), + 'StakeForQuotaWithCallback'); + assert.deepEqual(result, [ 'd1a4cce2809fdfb51652da66ba5718cf37f3441d5a39a99f9ab14b209206ab2c', true ]); + }); + it('StakeForQuotaWithCallback callback signature', function () { + const result = abi.decodeFunctionCall('callback StakeForQuotaWithCallback(bytes32 id, bool success)', Buffer.from('VLTtU9GkzOKAn9+1FlLaZrpXGM8380QdWjmpn5qxSyCSBqssAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=', 'base64').toString('hex'), '54b4ed53'); + assert.deepEqual(result, [ 'd1a4cce2809fdfb51652da66ba5718cf37f3441d5a39a99f9ab14b209206ab2c', true ]); }); }); - it('only one non-indexed token id', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': false, - 'inputs': [ - {'indexed': false, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} - ], - 'name': 'TestEvent', - 'type': 'event' - }, - '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a', - ['8b5075daac7054843301efa983d65ebb0a2ab0943c4464c5d90116bac31b558e']); + describe('encode2decode', function () { + it('uint256 type', function () { + const obj = ['23']; + const types = [{ name: 'jackpot', type: 'uint256' }]; + + const result1 = abi.encodeParameters(types, obj); + const result2 = abi.decodeParameters(types, result1); - assert.deepEqual(decodeResult, { - '0': 'tti_b0de22e5d54c92c43c3a9e54', - tti: 'tti_b0de22e5d54c92c43c3a9e54' + assert.deepEqual(result2, obj); }); - }); + it('uint256 uint32[2][3][4] type', function () { + const obj = [ + '23', + [[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]] + ]; + const types = [ + { name: 'jackpot', type: 'uint256' }, + { name: 'round', type: 'uint32[2][3][4]' } + ]; - it('only one indexed token id', function () { - const decodeResult = abi.decodeLog({ - 'anonymous': false, - 'inputs': [ - {'indexed': true, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} - ], - 'name': 'TestEvent', - 'type': 'event' - }, - '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a', - [ - '8b5075daac7054843301efa983d65ebb0a2ab0943c4464c5d90116bac31b558e', - '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a' ]); + const result1 = abi.encodeParameters(types, obj); + const result2 = abi.decodeParameters(types, result1); - assert.deepEqual(decodeResult, { - '0': 'tti_b0de22e5d54c92c43c3a9e54', - tti: 'tti_b0de22e5d54c92c43c3a9e54' + assert.deepEqual(result2, obj); }); - }); -}); + it('uint256 address[9] uint8 uint64 type', function () { + const obj = [ '500000000000000000', + [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ], + '2', + '2' ]; + const types = [ + { name: 'jackpot', type: 'uint256' }, + { name: 'addrs', type: 'address[9]' }, + { name: 'offset', type: 'uint8' }, + { name: 'round', type: 'uint64' } + ]; -describe('encodeFunctionCall', function () { - it('case 1', function () { - const result = abi.encodeFunctionCall({ - name: 'myMethod', - type: 'function', - inputs: [ { - type: 'uint256', - name: 'myNumber' - }, { - type: 'string', - name: 'myString' - } ] - }, [ '2345675643', 'Hello!%' ]); - assert.equal('96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', result); - }); - it('case 2', function () { - const result1 = abi.encodeFunctionCall([ { - name: 'myMethod', - type: 'function', - inputs: [ { - type: 'uint256', - name: 'myNumber' - }, { - type: 'string', - name: 'myString' - } ] - }, { - name: 'myethod', - type: 'function', - inputs: [ { - type: 'uint256', - name: 'myNumber' - }, { - type: 'string', - name: 'myString' - } ] - } ], [ '2345675643', 'Hello!%' ], 'myMethod'); - assert.equal('96173f6c000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', result1); - }); - it('case 3 int16[]', function () { - const encodeParameterResult14 = abi.encodeFunctionCall({ 'constant': false, 'inputs': [{ 'name': 'proposal', 'type': 'int16[]' }], 'name': 'vote', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, [[ -2, -2 ]]); - assert.equal('aa941d3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', encodeParameterResult14); - }); - it('case 4 int16[]', function () { - const encodeParameterResult14 = abi.encodeFunctionCall({ 'constant': false, 'inputs': [{ 'name': 'proposal', 'type': 'int16[]' }], 'name': 'vote', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, [[ -2, -9999 ]]); - assert.equal('aa941d3300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f1', encodeParameterResult14); + const result1 = abi.encodeParameters(types, obj); + assert.deepEqual(abi.decodeParameters(types, result1), obj); + }); + it('uint256 address[9] uint8 uint64 type string', function () { + const obj = [ '500000000000000000', + [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', + 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ], + '2', + '2' ]; + const types = JSON.stringify([ + { name: 'jackpot', type: 'uint256' }, + { name: 'addrs', type: 'address[]' }, + { name: 'offset', type: 'uint8' }, + { name: 'round', type: 'uint64' } + ]); + + const result1 = abi.encodeParameters(types, obj); + assert.deepEqual(abi.decodeParameters(types, result1), obj); + }); + it('string', function () { + const result = abi.encodeParameter('string', '15'); + assert.equal('15', abi.decodeParameter('string', result)); + }); + it('string', function () { + const result = abi.encodeParameter('string', '0x15'); + assert.equal('0x15', abi.decodeParameter('string', result)); + }); + it('string', function () { + const result = abi.encodeParameter('string', '我也圣诞节'); + assert.equal('我也圣诞节', abi.decodeParameter('string', result)); + }); + it('int8', function () { + const result = abi.encodeParameter('int8', -1); + assert.equal(-1, abi.decodeParameter('int8', result)); + }); + it('int8', function () { + const result = abi.encodeParameter('int', '-1999999999999999'); + assert.equal(-1999999999999999, abi.decodeParameter('int', result)); + }); + it('RegisterSBP', function () { + const _abi = { 'type': 'function', 'name': 'RegisterSBP', 'inputs': [ { 'name': 'sbpName', 'type': 'string' }, { 'name': 'blockProducingAddress', 'type': 'address' }, { 'name': 'rewardWithdrawAddress', 'type': 'address' } ] }; + const _data = 'QwdfvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAABugTBzH4D7fKee470/jQnv6Zh2KwAAAAAAAAAAAAAAAG6BMHMfgPt8p57jvT+NCe/pmHYrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMQ1NfVEVTVF9OT0RFAAAAAAAAAAAAAAAAAAAAAAAAAAA='; + const result = abi.encodeFunctionCall(_abi, + [ 'CS_TEST_NODE', 'vite_6e8130731f80fb7ca79ee3bd3f8d09efe998762b9e72ed1e5e', 'vite_6e8130731f80fb7ca79ee3bd3f8d09efe998762b9e72ed1e5e' ]); + assert.equal(result, Buffer.from(_data, 'base64').toString('hex')); + const result2 = abi.decodeFunctionCall(_abi, Buffer.from(_data, 'base64').toString('hex')); + assert.deepEqual(result2, [ 'CS_TEST_NODE', 'vite_6e8130731f80fb7ca79ee3bd3f8d09efe998762b9e72ed1e5e', 'vite_6e8130731f80fb7ca79ee3bd3f8d09efe998762b9e72ed1e5e' ]); + }); }); -}); -describe('encode2decode', function () { - it('array 1', function () { - const obj = ['23']; - const types = [{ name: 'jackpot', type: 'uint256' }]; + describe('getAbiByType', function () { + it('offchain', function () { + const type = 'offchain'; + const _data = abi.getAbiByType([ + { 'type': 'offchain', 'inputs': [{ 'type': 'address' }] }, + { 'type': 'constructor', 'inputs': [{ 'type': 'address' }] } + ], type); + + assert.equal(_data.type, type); + }); + it('constructor', function () { + const type = 'constructor'; + const _data = abi.getAbiByType([ + { 'type': 'offchain', 'inputs': [{ 'type': 'address' }] }, + { 'type': 'constructor', 'inputs': [{ 'type': 'address' }] } + ], type); + + assert.equal(_data.type, type); + }); + it('type is object', function () { + const type = 'constructor'; + const _data = abi.getAbiByType({ 'type': 'constructor', 'inputs': [{ 'type': 'address' }] }, type); - const result1 = abi.encodeParameters(types, obj); - const result2 = abi.decodeParameters(types, result1); + assert.equal(_data.type, type); + }); + it('empty type', function () { + const type = undefined; + const _data = abi.getAbiByType([ + { 'type': 'offchain', 'inputs': [{ 'type': 'address' }] }, + { 'type': 'constructor', 'inputs': [{ 'type': 'address' }] } + ], type); - assert.deepEqual(obj, result2); + assert.equal(_data, null); + }); }); - // it('uint32[2][3][4]', function () { - // const obj = [ - // // '23', - // [[[ 1, 2 ], [ 3, 4 ], [ 5, 6 ]], [[ 7, 8 ], [ 9, 10 ], [ 11, 12 ]], [[ 13, 14 ], [ 15, 16 ], [ 17, 18 ]], [[ 19, 20 ], [ 21, 22 ], [ 23, 24 ]]] - // ]; - // const types = [ - // // { name: 'jackpot', type: 'uint256' }, - // { name: 'round', type: 'uint32[2][3][4]' } - // ]; - // const result1 = abi.encodeParameters(types, obj); - // // console.log(result1); - // const result2 = abi.decodeParameters(types, result1); + describe('getAbiByName', function () { + it('empty method name', function () { + const name = undefined; + const _data = abi.getAbiByName([ + { name: 'myMethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, { type: 'string', name: 'myString'} ]}, + { name: 'myethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, {type: 'string', name: 'myString'} ]} + ], name); + + assert.equal(_data, null); + }); + it('method doesn\'t exist', function () { + const name = 'myethod'; + const _data = abi.getAbiByName([ + { name: 'myMethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, { type: 'string', name: 'myString'} ]} + ], name); - // assert.deepEqual(obj, result2); - // }); - it('abi encodeParameters address[9] to decodeParameters', function () { - const obj = [ '500000000000000000', - [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ], - '2', - '2' ]; - const types = [ - { name: 'jackpot', type: 'uint256' }, - { name: 'addrs', type: 'address[9]' }, - { name: 'offset', type: 'uint8' }, - { name: 'round', type: 'uint64' } - ]; + assert.equal(_data, null); + }); + it('abi is array', function () { + const name = 'myMethod'; + const _data = abi.getAbiByName([ + { name: 'myMethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, { type: 'string', name: 'myString'} ]}, + { name: 'myethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, {type: 'string', name: 'myString'} ]} + ], name); - const result1 = abi.encodeParameters(types, obj); - assert.deepEqual(obj, abi.decodeParameters(types, result1)); - }); - it('abi encodeParameters address[] to decodeParameters', function () { - const obj = [ '500000000000000000', - [ 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930', - 'vite_2fe3a97151de7a57b5e8c58a5f32d602efe4dc7277e12c0930' ], - '2', - '2' ]; - const types = [ - { name: 'jackpot', type: 'uint256' }, - { name: 'addrs', type: 'address[]' }, - { name: 'offset', type: 'uint8' }, - { name: 'round', type: 'uint64' } - ]; + assert.equal(_data.name, name); + }); + it('abi is object', function () { + const name = 'myMethod'; + const _data = abi.getAbiByName({ name: 'myMethod', type: 'function', inputs: [{type: 'uint256', name: 'myNumber'}]}, name); - const result1 = abi.encodeParameters(types, obj); - assert.deepEqual(obj, abi.decodeParameters(types, result1)); - }); - it('case 1', function () { - const result = abi.encodeParameter('string', '15'); - assert.equal('15', abi.decodeParameter('string', result)); - }); - it('case 2', function () { - const result = abi.encodeParameter('string', '0x15'); - assert.equal('0x15', abi.decodeParameter('string', result)); - }); - it('case 3', function () { - const result = abi.encodeParameter('string', '我也圣诞节'); - assert.equal('我也圣诞节', abi.decodeParameter('string', result)); - }); - it('case 4', function () { - const result = abi.encodeParameter('int8', -1); - assert.equal(-1, abi.decodeParameter('int8', result)); - }); - it('case 5', function () { - const result = abi.encodeParameter('int', '-1999999999999999'); - assert.equal(-1999999999999999, abi.decodeParameter('int', result)); + assert.equal(_data.name, name); + }); + it('abi is wrong', function () { + try { + const name = 'myMethod'; + abi.getAbiByName('myMethod', name); + } catch (err) { + assert.equal(err.message.indexOf('jsonFragment should be an array or object') !== -1, true); + } + }); }); -}); - -describe('getAbiByType', function () { - it('offchain', function () { - const type = 'offchain'; - const _data = abi.getAbiByType([ - { 'type': 'offchain', 'inputs': [{ 'type': 'address' }] }, - { 'type': 'constructor', 'inputs': [{ 'type': 'address' }] } - ], type); - assert.equal(_data.type, type); + describe('catch error', function () { + it('uint', function () { + assert.throws(() => abi.encodeParameter('uint', '-2'), new Error('value out-of-bounds: -2')); + }); + it('int -9999', function () { + assert.throws(() => abi.encodeParameter('int8', '-9999'), new Error('value out-of-bounds: -9999')); + }); + it('int 9999', function () { + assert.throws(() => abi.encodeParameter('9999', '9999'), new Error('illegal type: 9999')); + }); + it('int -19999999999999999999999999999999999999999999999999999999999999', function () { + assert.doesNotThrow(() => { + assert.equal(1, abi.decodeParameter('int8', 'fffffffffffff38dd0f10627f5529bdb2c52d4846810af0ac000000000000001')); + }, new Error('value out-of-bounds: -19999999999999999999999999999999999999999999999999999999999999')); + }); + it('no function name', function () { + assert.throws(() => abi.encodeFunctionCall({ 'constant': false, 'inputs': [{ 'name': 'proposal', 'type': 'int16[]' }], 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function' }, + [[ -2, -2 ]]), new Error('invalid identifier: undefined')); + }); + it('no constructor', function () { + assert.throws(() => abi.encodeConstructor([{ 'type': 'function', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }], ['tti_5649544520544f4b454e6e40']), new Error('abi has no constructor')); + }); + it('no matching function name', function () { + assert.throws(() => abi.decodeOffchainOutput([ 'function getData(tokenId id) returns (uint256 amount)', 'offchain dummy(tokenId id) returns (uint256 amount)' ], '000000000000000000000000000000000000000000000000000000000000007b', 'getData'), new Error('no matching function: getData')); + }); + it('no matching function sighash', function () { + assert.throws(() => abi.decodeFunctionCall(['callback StakeForQuotaWithCallback(bytes32 id, bool success)'], Buffer.from('VLTtU9GkzOKAn9+1FlLaZrpXGM8380QdWjmpn5qxSyCSBqssAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=', 'base64').toString('hex'), + '54b4ed50'), new Error('no matching sighash: 54b4ed50')); + }); + it('multiple functions with same name', function () { + assert.throws(() => abi.decodeFunctionCall([ 'callback StakeForQuotaWithCallback(bytes32 id, bool success)', 'function StakeForQuotaWithCallback(address beneficiary, uint64 stakeHeight)' ], Buffer.from('VLTtU9GkzOKAn9+1FlLaZrpXGM8380QdWjmpn5qxSyCSBqssAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=', 'base64').toString('hex'), + 'StakeForQuotaWithCallback'), new Error('multiple matching functions: StakeForQuotaWithCallback')); + }); }); - it('constructor', function () { - const type = 'constructor'; - const _data = abi.getAbiByType([ - { 'type': 'offchain', 'inputs': [{ 'type': 'address' }] }, - { 'type': 'constructor', 'inputs': [{ 'type': 'address' }] } - ], type); - assert.equal(_data.type, type); + describe('decodeFunctionOutput', function () { + it('empty string[] json', function () { + const result = abi.decodeFunctionOutput(JSON.stringify([{'inputs': [{'internalType': 'string[]', 'name': 'input', 'type': 'string[]'}], 'name': 'strArr0', 'outputs': [{'internalType': 'string[]', 'name': '', 'type': 'string[]'}], 'stateMutability': 'view', 'type': 'function'}]), '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [[]]); + }); + it('string[1] json', function () { + const result = abi.decodeFunctionOutput(JSON.stringify({'inputs': [{'internalType': 'string[1]', 'name': 'input', 'type': 'string[1]'}], 'name': 'strArr1Static', 'outputs': [{'internalType': 'string[1]', 'name': '', 'type': 'string[1]'}], 'stateMutability': 'view', 'type': 'function'}), '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047573657200000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [['user']]); + }); + it('uint256[5] string[]', function () { + const result = abi.decodeFunctionOutput([{'inputs': [ {'internalType': 'uint256[5]', 'name': 'input1', 'type': 'uint256[5]'}, {'internalType': 'string[]', 'name': 'input2', 'type': 'string[]'} ], 'name': 'strIntArr5I2R2DynamicAndStatic', 'outputs': [ {'internalType': 'uint256[5]', 'name': '', 'type': 'uint256[5]'}, {'internalType': 'string[]', 'name': 'r1', 'type': 'string[]'} ], 'stateMutability': 'view', 'type': 'function'}], '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000', 'strIntArr5I2R2DynamicAndStatic'); + assert.deepEqual(result, [[ 0, 1, 2, 3, 4 ], [ 'alice', 'alice', 'alice', 'alice', 'alice' ]]); + }); + it('string[3][]', function () { + const result = abi.decodeFunctionOutput({'inputs': [{'internalType': 'string[3][]', 'name': 'input', 'type': 'string[3][]'}], 'name': 'strArr2DStaticWithInput', 'outputs': [{'internalType': 'string[3][]', 'name': '', 'type': 'string[3][]'}], 'stateMutability': 'view', 'type': 'function'}, '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c6963650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000', 'strArr2DStaticWithInput'); + assert.deepEqual(result, [[[ 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice' ], [ 'alice', 'alice', 'alice' ]]]); + }); + it('uint256[2][][3]', function () { + const result = abi.decodeFunctionOutput([ + {'inputs': [ {'internalType': 'uint256[5]', 'name': 'input1', 'type': 'uint256[5]'}, {'internalType': 'string[]', 'name': 'input2', 'type': 'string[]'} ], 'name': 'strIntArr5I2R2DynamicAndStatic', 'outputs': [ {'internalType': 'uint256[5]', 'name': '', 'type': 'uint256[5]'}, {'internalType': 'string[]', 'name': '', 'type': 'string[]'} ], 'stateMutability': 'view', 'type': 'function'}, + {'inputs': [{'internalType': 'uint256[2][][3]', 'name': 'input', 'type': 'uint256[2][][3]'}], 'name': 'intArr3DStaticWithInput', 'outputs': [{'internalType': 'uint256[2][][3]', 'name': '', 'type': 'uint256[2][][3]'}], 'stateMutability': 'pure', 'type': 'function'} ], + '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002', + 'intArr3DStaticWithInput'); + assert.deepEqual(result, [[[[ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]]]]); + }); + it('struct simple', function () { + const result = abi.decodeFunctionOutput([{'name': 'getBet', 'outputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'components': [ {'internalType': 'string', 'name': 'name', 'type': 'string'}, {'internalType': 'address', 'name': 'addr', 'type': 'address'} ], 'internalType': 'struct Hello.User[]', 'name': 'users', 'type': 'tuple[]'}, {'internalType': 'string[][3][]', 'name': 'result', 'type': 'string[][3][]'} ], 'internalType': 'struct Hello.BetLimit', 'name': '', 'type': 'tuple'}], 'stateMutability': 'pure', 'type': 'function'}], '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [{ lowerLimit: 1, upperLimit: 2, tipPer: 3, users: [ {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' }, {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' } ], result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]]}]); + }); + it('struct complex signature', function () { + const result = abi.decodeFunctionOutput(['function getBet() pure returns (tuple(uint256 lowerLimit, uint256 upperLimit, uint256 tipPer, tuple(string name, address addr)[] users, string[][3][] result))'], '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000005a600b6c5103f242107b6eebf8aa290bda86800a0000000000000000000000000000000000000000000000000000000000000000046e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005616c696365000000000000000000000000000000000000000000000000000000'); + assert.deepEqual(result, [{ lowerLimit: 1, upperLimit: 2, tipPer: 3, users: [ {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' }, {name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' } ], result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]]}]); + }); }); - it('type is object', function () { - const type = 'constructor'; - const _data = abi.getAbiByType({ 'type': 'constructor', 'inputs': [{ 'type': 'address' }] }, type); - assert.equal(_data.type, type); + describe('offchain', function () { + it('encode tokenId named', function () { + const result = abi.encodeOffchainCall([{ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }], ['tti_5649544520544f4b454e6e40'], 'getData'); + assert.deepEqual('a0a3fe85000000000000000000000000000000000000000000005649544520544f4b454e', result); + }); + it('encode tokenId', function () { + const result = abi.encodeOffchainCall([{ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }], ['tti_5649544520544f4b454e6e40']); + assert.deepEqual('a0a3fe85000000000000000000000000000000000000000000005649544520544f4b454e', result); + }); + it('decode output uint256 named', function () { + const result = abi.decodeOffchainOutput([{ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }], '000000000000000000000000000000000000000000000000000000000000007b', 'getData'); + assert.deepEqual(result, [123]); + }); + it('decode output uint256 json named', function () { + const result = abi.decodeOffchainOutput(JSON.stringify({ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }), '000000000000000000000000000000000000000000000000000000000000007b', 'getData'); + assert.deepEqual(result, [123]); + }); + it('decode output uint256 named signature', function () { + const result = abi.decodeOffchainOutput({ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }, '000000000000000000000000000000000000000000000000000000000000007b', + 'getData(tokenId)'); + assert.deepEqual(result, [123]); + }); + it('decode output uint256 named sighash', function () { + const result = abi.decodeOffchainOutput({ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }, '000000000000000000000000000000000000000000000000000000000000007b', + 'a0a3fe85'); + assert.deepEqual(result, [123]); + }); + it('decode output uint256 signature', function () { + const result = abi.decodeOffchainOutput(['offchain getData(tokenId id) returns (uint256 amount)'], '000000000000000000000000000000000000000000000000000000000000007b', 'getData(tokenId id) returns (uint256 amount)'); + assert.deepEqual(result, [123]); + }); + it('decode output uint256 signature named', function () { + const result = abi.decodeOffchainOutput([ 'getter getData(tokenId id) returns (uint256)', 'getter dummy(tokenId id) returns (uint256)' ], '000000000000000000000000000000000000000000000000000000000000007b', 'getData'); + assert.deepEqual([123], result); + }); + it('encode uint8[] bytes named', function () { + const result = abi.encodeOffchainCall([ + { 'type': 'constructor', 'name': 'myMethods', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, + { 'type': 'constructor', 'name': 'myMetod', 'inputs': [{ 'type': 'bytes' }] }, + { 'type': 'offchain', 'name': 'myMethowed', 'inputs': [ { 'type': 'uint8[]' }, { 'type': 'bytes' } ] }, + { 'type': 'receive', 'inputs': [], 'payable': true } + ], [[ '34', '43' ], '324567ff' ], 'myMethowed'); + assert.equal('4dbd3ab8000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002b0000000000000000000000000000000000000000000000000000000000000004324567ff00000000000000000000000000000000000000000000000000000000', result); + }); }); - it('empty type', function () { - const type = undefined; - const _data = abi.getAbiByType([ - { 'type': 'offchain', 'inputs': [{ 'type': 'address' }] }, - { 'type': 'constructor', 'inputs': [{ 'type': 'address' }] } - ], type); - assert.equal(_data, null); + describe('encodeConstructor', function () { + it('address', function () { + const result = abi.encodeConstructor([{ 'type': 'constructor', 'inputs': [{ 'name': 'owner', 'type': 'address' }] }], ['vite_ab24ef68b84e642c0ddca06beec81c9acb1977bbd7da27a87a']); + assert.equal('0000000000000000000000ab24ef68b84e642c0ddca06beec81c9acb1977bb00', result); + }); + it('address json', function () { + const result = abi.encodeConstructor(JSON.stringify({ 'type': 'constructor', 'inputs': [{ 'name': 'owner', 'type': 'address' }] }), ['vite_ab24ef68b84e642c0ddca06beec81c9acb1977bbd7da27a87a']); + assert.equal('0000000000000000000000ab24ef68b84e642c0ddca06beec81c9acb1977bb00', result); + }); + it('address signature', function () { + const result = abi.encodeConstructor('constructor(address owner)', ['vite_ab24ef68b84e642c0ddca06beec81c9acb1977bbd7da27a87a']); + assert.equal('0000000000000000000000ab24ef68b84e642c0ddca06beec81c9acb1977bb00', result); + }); }); -}); -describe('getAbiByName', function () { - it('empty method name', function () { - const name = undefined; - const _data = abi.getAbiByName([ - { name: 'myMethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, { type: 'string', name: 'myString'} ]}, - { name: 'myethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, {type: 'string', name: 'myString'} ]} - ], name); + describe('encodeLogFilter', function () { + it('indexed uint256', function () { + const result = abi.encodeLogFilter({ + 'anonymous': false, + 'inputs': [ + {'indexed': true, 'internalType': 'uint256', 'name': 't', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'} + ], + 'name': 'Event3', + 'type': 'event' + }, + ['1']); - assert.equal(_data, null); - }); - it('method doesn\'t exist', function () { - const name = 'myethod'; - const _data = abi.getAbiByName([ - { name: 'myMethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, { type: 'string', name: 'myString'} ]} - ], name); + assert.deepEqual(result, [ + 'ff75de284617dcb8120f62e0ab99092112d2fa831082b3cb4d6703a07a757a88', + '0000000000000000000000000000000000000000000000000000000000000001' + ]); + }); + it('indexed uint256 string', function () { + const result = abi.encodeLogFilter({ + 'anonymous': false, + 'inputs': [ + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': true, 'internalType': 'uint256', 'name': 't1', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'}, + {'indexed': true, 'internalType': 'string', 'name': 't2', 'type': 'string'} + ], + 'name': 'Event4', + 'type': 'event' + }, + [ '1', 'hello world' ]); + assert.deepEqual(result, [ + 'b787fae491b126a61d9e5c4f03e16463e6f1f985d0682dd2d1a844331b539e9c', + '0000000000000000000000000000000000000000000000000000000000000001', + '256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610' + ]); + }); + it('indexed uint256 string multiple inputs', function () { + const result = abi.encodeLogFilter({ + 'anonymous': false, + 'inputs': [ + {'indexed': false, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': true, 'internalType': 'uint256', 'name': 't1', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 's', 'type': 'string'}, + {'indexed': true, 'internalType': 'string', 'name': 't2', 'type': 'string'} + ], + 'name': 'Event4', + 'type': 'event' + }, + [[ '1', 100 ], [ 'hello world', 'name', 'alice' ]]); + assert.deepEqual(result, [ + 'b787fae491b126a61d9e5c4f03e16463e6f1f985d0682dd2d1a844331b539e9c', + [ '0000000000000000000000000000000000000000000000000000000000000001', + '0000000000000000000000000000000000000000000000000000000000000064' ], + [ '256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610', + '3adaf70d6a60eba6aaa6a1884c382ae32b223557ccaa2f3fcab6aec6c2fca21f', + 'e11d814979372c883b50bdb0ffadb1eaf0898bf54fd4fbf298af126fbabbda4c' ] + ]); + }); + it('anonymous indexed uint256', function () { + const result = abi.encodeLogFilter({ + 'anonymous': true, + 'inputs': [ + {'indexed': true, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'} + ], + 'name': 'AnonymousEvent', + 'type': 'event' + }, + [123]); - assert.equal(_data, null); - }); - it('abi is array', function () { - const name = 'myMethod'; - const _data = abi.getAbiByName([ - { name: 'myMethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, { type: 'string', name: 'myString'} ]}, - { name: 'myethod', type: 'function', inputs: [ {type: 'uint256', name: 'myNumber'}, {type: 'string', name: 'myString'} ]} - ], name); + assert.deepEqual(result, ['000000000000000000000000000000000000000000000000000000000000007b']); + }); + it('indexed tokenId', function () { + const result = abi.encodeLogFilter({ + 'anonymous': false, + 'inputs': [ + {'indexed': true, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} + ], + 'name': 'TestEvent', + 'type': 'event' + }, + ['tti_b0de22e5d54c92c43c3a9e54']); - assert.equal(_data.name, name); + assert.deepEqual(result, [ + '8b5075daac7054843301efa983d65ebb0a2ab0943c4464c5d90116bac31b558e', + '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a' ]); + }); + it('indexed bytes', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'bytes', 'name': 'user', 'type': 'bytes'}], 'name': 'DeployedBytes', 'type': 'event'}], + [Buffer.from('name')]); + assert.deepEqual(result, [ + '360bba44e4490fae37d6444482aa67cf5ec7418850531522450c3805b8e5425c', + '3adaf70d6a60eba6aaa6a1884c382ae32b223557ccaa2f3fcab6aec6c2fca21f' ]); + }); + it('indexed bytes two inputs', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'bytes', 'name': 'user', 'type': 'bytes'}], 'name': 'DeployedBytes', 'type': 'event'}], + [[ Buffer.from('name'), Buffer.from('alice') ]]); + assert.deepEqual(result, [ + '360bba44e4490fae37d6444482aa67cf5ec7418850531522450c3805b8e5425c', + [ '3adaf70d6a60eba6aaa6a1884c382ae32b223557ccaa2f3fcab6aec6c2fca21f', + 'e11d814979372c883b50bdb0ffadb1eaf0898bf54fd4fbf298af126fbabbda4c' ]]); + }); + it('indexed string[]', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'string[]', 'name': 'user', 'type': 'string[]'}], 'name': 'DeployedUser', 'type': 'event'}], + [[ 'alice', 'alice' ]], 'DeployedUser'); + assert.deepEqual(result, [ + '77eaa9d8538de877bc481f8d5cc7ed2d439983f13f0f0e1cb77ddf54b79a864d', + '9fdc9b04e2582fb90d298fa3a2f92d1f88fd80f130456a48ca49d330d6fb320a' ]); // storage version is incorrect + }); + it('indexed string[] empty', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'string[]', 'name': 'user', 'type': 'string[]'}], 'name': 'DeployedUser', 'type': 'event'}], + [], 'DeployedUser'); + assert.deepEqual(result, [ + '77eaa9d8538de877bc481f8d5cc7ed2d439983f13f0f0e1cb77ddf54b79a864d']); + }); + it('indexed string[][3][]', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'string[][3][]', 'name': 'user', 'type': 'string[][3][]'}], 'name': 'DeployedUser', 'type': 'event'}], + [[[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]]], 'DeployedUser'); + assert.deepEqual(result, [ + '26e592291c0438481e80c96c7790f6ccfd7931762a63f1a10c2224d26a815c76', + '11e5a0f06c70fd30233500c396ca3f2d0ac3bfca4c38d836c9b12361b9b8890e' ]); // storage version is incorrect + }); + it('indexed uint256[2]', function () { + const result = abi.encodeLogFilter({'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'uint256[2]', 'name': 'user', 'type': 'uint256[2]'}], 'name': 'DeployedIntUserShort', 'type': 'event'}, + [[ 1, 2 ]]); + assert.deepEqual(result, [ + '312867fc6aeb487e19b5cfff805ccc75517e4364d08b6ed0c0bd21af850d56a2', + '3b2badc3d858b0b6120818c8c8c0c4c5f82376b8cfcd213be46db8e6321febc9' ]); // for uint256[], storage version is incorrect + }); + it('indexed uint256[2][3][3]', function () { + const result = abi.encodeLogFilter({'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'uint256[2][3][3]', 'name': 'user', 'type': 'uint256[2][3][3]'}], 'name': 'DeployedIntUser', 'type': 'event'}, + [[[[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]]]]); + assert.deepEqual(result, [ + '72618aebac9fd16dbb9c7c19fc54bd0c5c0743058e1f3f68a3bb4aba910e7e8b', + '195100fac46022427379342d048e965bb47aaae41eb2c33e54787006991128b9' ]); // memory version is incorrect + }); + it('indexed struct(string,address)', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'components': [ {'internalType': 'string', 'name': 'name', 'type': 'string'}, {'internalType': 'address', 'name': 'addr', 'type': 'address'} ], 'indexed': true, 'internalType': 'struct Hello.User', 'name': 'user', 'type': 'tuple'}], 'name': 'DeployedUser', 'type': 'event'}], + [{ name: 'name', addr: 'vite_5a600b6c5103f242107b6eebf8aa290bda86800adb0c264ab6' }], + 'DeployedUser'); + assert.deepEqual(result, [ + 'a726de6a27282e9f2fd40ef5acb830570c4692fb93330688f812d9de29c4a4de', + 'd24057e115ec2936b95a95de18f6272a7ff18a572a393f3fecb9c517e322be95' ]); + }); + it('indexed struct(uint256,uint256,uint256,string[][3][])', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'internalType': 'string[][3][]', 'name': 'result', 'type': 'string[][3][]'} ], 'indexed': true, 'internalType': 'struct Hello.BetLimit', 'name': 'bet', 'type': 'tuple'}], 'name': 'DeployedBet', 'type': 'event'}], + [{ lowerLimit: 1, upperLimit: 2, tipPer: 3, result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]] }], + 'DeployedBet'); + assert.deepEqual(result, [ + '308561ee2a3c3ea5df3689e7131e0ca7006467c81f664528bd01c96f3783a6ef', + '91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0' ]); // storage version is incorrect + }); + it('indexed struct(uint256,uint256,uint256,string[1][3][2])', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [{'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'internalType': 'string[1][3][2]', 'name': 'result', 'type': 'string[1][3][2]'} ], 'indexed': true, 'internalType': 'struct Hello.BetLimit', 'name': 'bet', 'type': 'tuple'}], 'name': 'DeployedBet', 'type': 'event'}], + [{ lowerLimit: 1, upperLimit: 2, tipPer: 3, result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]] }], + 'DeployedBet'); + assert.deepEqual(result, [ + '1d8e14596183a6d73bc8760a43cdaf6992e6cb318cecec67f4b6bcb31fe039d5', + '91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0' ]); + }); + it('indexed struct uint256[2][3][3] tokenId multiple inputs', function () { + const result = abi.encodeLogFilter([{'anonymous': false, 'inputs': [ {'components': [ {'internalType': 'uint256', 'name': 'lowerLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'upperLimit', 'type': 'uint256'}, {'internalType': 'uint256', 'name': 'tipPer', 'type': 'uint256'}, {'internalType': 'string[1][3][2]', 'name': 'result', 'type': 'string[1][3][2]'} ], 'indexed': true, 'internalType': 'struct Hello.BetLimit', 'name': 'bet', 'type': 'tuple'}, {'indexed': true, 'internalType': 'uint256[2][3][3]', 'name': 'user', 'type': 'uint256[2][3][3]'}, {'indexed': true, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} ], 'name': 'DeployedBet', 'type': 'event'}], + [[{ lowerLimit: 1, upperLimit: 2, tipPer: 3, result: [[['alice'], ['alice'], ['alice']], [['alice'], ['alice'], ['alice']]] }], + [[[[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]], [[ 1, 2 ], [ 1, 2 ], [ 1, 2 ]]], [[[ 10, 20 ], [ 10, 20 ], [ 10, 20 ]], [[ 10, 20 ], [ 10, 20 ], [ 10, 20 ]], [[ 10, 20 ], [ 10, 20 ], [ 10, 20 ]]]], + 'tti_b0de22e5d54c92c43c3a9e54' ], + 'DeployedBet'); + assert.deepEqual(result, [ + 'd2ad7970a01e5f873feb83472ba67d1df2e0c02f57651d00a29847058b956c3d', + ['91ac0b2bf8c6dc8d37d0bc48a0eacaf6a7ed5bec9be59086116c6f23eca8aaf0'], + [ '195100fac46022427379342d048e965bb47aaae41eb2c33e54787006991128b9', + 'ed142eea076cea6c75f69c6c4fa853888a181eeef58f2c61eba439c0d10f7954' ], + '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a' + ]); + }); }); - it('abi is object', function () { - const name = 'myMethod'; - const _data = abi.getAbiByName({ name: 'myMethod', type: 'function', inputs: [{type: 'uint256', name: 'myNumber'}]}, name); - assert.equal(_data.name, name); - }); - it('abi is wrong', function () { - try { - const name = 'myMethod'; - abi.getAbiByName('myMethod', name); - } catch (err) { - assert.equal(err.message.indexOf('jsonInterfaces need array or object') !== -1, true); - } + describe('format', function () { + it('abi', function () { + const _abi = abi.Abi.from([ 'function getBet() pure returns (tuple(uint256 lowerLimit, uint256 upperLimit, uint256 tipPer, tuple(string name, address addr)[] users, string[][3][] result))', + {'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'uint256[2][3][3]', 'name': 'user', 'type': 'uint256[2][3][3]'}], 'name': 'DeployedIntUser', 'type': 'event'} ]); + assert.deepEqual(_abi.format(), [ + 'function getBet() pure returns (tuple(uint256 lowerLimit, uint256 upperLimit, uint256 tipPer, tuple(string name, address addr)[] users, string[][3][] result))', + 'event DeployedIntUser(uint256[2][3][3] indexed user)' + ]); + assert.equal(_abi.format(FormatTypes.Json), + '[{"type":"function","name":"getBet","constant":true,"stateMutability":"pure","payable":false,"inputs":[],"outputs":[{"type":"tuple","components":[{"type":"uint256","name":"lowerLimit"},{"type":"uint256","name":"upperLimit"},{"type":"uint256","name":"tipPer"},{"type":"tuple[]","name":"users","components":[{"type":"string","name":"name"},{"type":"address","name":"addr"}]},{"type":"string[][3][]","name":"result"}]}]},{"type":"event","anonymous":false,"name":"DeployedIntUser","inputs":[{"type":"uint256[2][3][3]","name":"user","indexed":true}]}]'); + assert.throws(() => _abi.format(FormatTypes.Sighash), new Error('interface does not support formatting sighash')); + }); + it('abi fragment', function () { + const _abi = abi.Abi.from([ 'function getBet() pure returns (tuple(uint256 lowerLimit, uint256 upperLimit, uint256 tipPer, tuple(string name, address addr)[] users, string[][3][] result))', + {'anonymous': false, 'inputs': [{'indexed': true, 'internalType': 'uint256[2][3][3]', 'name': 'user', 'type': 'uint256[2][3][3]'}], 'name': 'DeployedIntUser', 'type': 'event'}, + { 'type': 'constructor', 'inputs': [{ 'name': 'owner', 'type': 'address' }]} ]); + assert.equal(_abi.deploy.format(FormatTypes.Full), 'constructor(address owner)'); + assert.equal(_abi.deploy.format(FormatTypes.Json), '{"type":"constructor","payable":false,"inputs":[{"type":"address","name":"owner"}]}'); + assert.equal(_abi.getEvent('DeployedIntUser').format(FormatTypes.Minimal), 'event DeployedIntUser(uint256[2][3][3] indexed)'); + assert.equal(_abi.getFunction('getBet').format(FormatTypes.Sighash), 'getBet()'); + assert.equal(_abi.getFunction('getBet').format(FormatTypes.Json), '{"type":"function","name":"getBet","constant":true,"stateMutability":"pure","payable":false,"inputs":[],"outputs":[{"type":"tuple","components":[{"type":"uint256","name":"lowerLimit"},{"type":"uint256","name":"upperLimit"},{"type":"uint256","name":"tipPer"},{"type":"tuple[]","name":"users","components":[{"type":"string","name":"name"},{"type":"address","name":"addr"}]},{"type":"string[][3][]","name":"result"}]}]}'); + }); + it('fragments', function () { + const _receive = DefaultFragment.from({'stateMutability': 'payable', 'type': 'receive'}); + assert.equal(_receive.format(), 'receive()'); + assert.equal(_receive.format(FormatTypes.Full), 'receive() payable'); + const _fallback = DefaultFragment.from('fallback()'); + assert.equal(_fallback.format(FormatTypes.Json), '{"type":"fallback","payable":false,"inputs":[]}'); + const _deploy = ConstructorFragment.from({ 'type': 'constructor', 'inputs': [{ 'name': 'owner', 'type': 'address' }] }); + assert.equal(_deploy.format(FormatTypes.Minimal), 'constructor(address)'); + const _deploy2 = ConstructorFragment.from('constructor(address owner)'); + assert.equal(_deploy2.format(FormatTypes.Json), '{"type":"constructor","payable":false,"inputs":[{"type":"address","name":"owner"}]}'); + const _function = DefaultFragment.from({ 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }); + assert.equal(_function.format(FormatTypes.Minimal), 'function singleParam(address)'); + const _function2 = FunctionFragment.from({ 'type': 'function', 'name': 'singleParam', 'inputs': [{ 'name': 'param1', 'type': 'address' }] }); + assert.equal(_function2.format(FormatTypes.Full), 'function singleParam(address param1)'); + const _function3 = FunctionFragment.from('singleParam(address param1)'); + assert.equal(_function3.format(FormatTypes.Json), '{"type":"function","name":"singleParam","constant":false,"payable":false,"inputs":[{"type":"address","name":"param1"}],"outputs":[]}'); + const _offchain = OffchainFragment.from({ 'type': 'offchain', 'name': 'getData', 'inputs': [{ 'name': 'id', 'type': 'tokenId' }], 'outputs': [{ 'name': 'amount', 'type': 'uint256' }] }); + assert.equal(_offchain.format(FormatTypes.Full), 'getter getData(tokenId id) returns (uint256 amount)'); + const _offchain2 = OffchainFragment.from('getData(tokenId id) returns (uint256 amount)'); + assert.equal(_offchain2.format(FormatTypes.Json), '{"type":"offchain","name":"getData","inputs":[{"type":"tokenId","name":"id"}],"outputs":[{"type":"uint256","name":"amount"}]}'); + const _event = EventFragment.from({'anonymous': false, 'inputs': [{'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'}], 'name': 'Event1', 'type': 'event'}); + assert.equal(_event.format(FormatTypes.Full), 'event Event1(string data)'); + const _event2 = EventFragment.from('Event1(string indexed data)'); + assert.equal(_event2.format(FormatTypes.Json), '{"type":"event","anonymous":false,"name":"Event1","inputs":[{"type":"string","name":"data","indexed":true}]}'); + const _event3 = EventFragment.from('AnonymousEvent(uint256 i,string data) anonymous'); + assert.equal(_event3.format(FormatTypes.Json), '{"type":"event","anonymous":true,"name":"AnonymousEvent","inputs":[{"type":"uint256","name":"i"},{"type":"string","name":"data"}]}'); + }); + it('param', function () { + const _type = ParamType.from({ name: 'addrs', type: 'address[9]' }); + assert.equal(_type.format(), 'address[9]'); + const _type2 = ParamType.from('uint8 id'); + assert.equal(_type2.format(FormatTypes.Json), '{"type":"uint8","name":"id"}'); + const _type3 = ParamType.from('{"type":"uint8","name":"id"}'); + assert.equal(_type3.format(FormatTypes.Full), 'uint8 id'); + }); }); -}); -describe('catch error', function () { - it('uint', function () { - try { - abi.encodeParameter('uint', '-2'); - } catch (err) { - assert.equal(err.message.indexOf('Uint shouldn\'t be a negative number') !== -1, true); - } + describe('encodeFunctionResult', function () { + it('empty string[]', function () { + const _abi = abi.Abi.from([{ + 'inputs': [{ + 'internalType': 'string[]', + 'name': 'input', + 'type': 'string[]' + }], + 'name': 'strArr0', + 'outputs': [{'internalType': 'string[]', 'name': '', 'type': 'string[]'}], + 'stateMutability': 'view', + 'type': 'function' + }]); + assert.equal(_abi.encodeFunctionResult('strArr0', [[]]), '00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000'); + }); + it('string[1] json', function () { + const _abi = abi.Abi.from(JSON.stringify({ + 'inputs': [{ + 'internalType': 'string[1]', + 'name': 'input', + 'type': 'string[1]' + }], + 'name': 'strArr1Static', + 'outputs': [{'internalType': 'string[1]', 'name': '', 'type': 'string[1]'}], + 'stateMutability': 'view', + 'type': 'function' + })); + assert.equal(_abi.encodeFunctionResult('strArr1Static(string[1])', [['user']]), '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047573657200000000000000000000000000000000000000000000000000000000'); + }); }); - it('int', function () { - try { - abi.encodeParameter('int8', '-9999'); - } catch (err) { - assert.equal(err.message.indexOf('Out of range') !== -1, true); - } + + describe('encodeLog', function () { + it('string', function () { + const _abi = abi.Abi.from({'anonymous': false, 'inputs': [{'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'}], 'name': 'Event1', 'type': 'event'}); + assert.deepEqual(_abi.encodeEventLog('Event1', ['hello world']), + { + data: '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + topics: ['30e00162ff22a0d2aaa98f7013fc6dcb0bfae6a56ed30e35c5ea19326211a1a9'] + }); + }); + it('tokenId indexed', function () { + const _abi = abi.Abi.from({ + 'anonymous': false, + 'inputs': [ + {'indexed': true, 'internalType': 'tokenId', 'name': 'tti', 'type': 'tokenId'} + ], + 'name': 'TestEvent', + 'type': 'event' + }); + assert.deepEqual(_abi.encodeEventLog('TestEvent(tokenId)', ['tti_b0de22e5d54c92c43c3a9e54']), + { + data: '', + topics: [ + '8b5075daac7054843301efa983d65ebb0a2ab0943c4464c5d90116bac31b558e', + '00000000000000000000000000000000000000000000b0de22e5d54c92c43c3a' ] + }); + }); + it('uint256 indexed string anonymous', function () { + const _abi = abi.Abi.from({ + 'anonymous': true, + 'inputs': [ + {'indexed': true, 'internalType': 'uint256', 'name': 'i', 'type': 'uint256'}, + {'indexed': false, 'internalType': 'string', 'name': 'data', 'type': 'string'} + ], + 'name': 'AnonymousEvent', + 'type': 'event' + }); + assert.deepEqual(_abi.encodeEventLog('AnonymousEvent(uint256,string)', [ 123, 'hello world' ]), + { + data: '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000', + topics: ['000000000000000000000000000000000000000000000000000000000000007b'] + }); + }); }); - it('int', function () { - try { - abi.encodeParameter('int8', '9999'); - } catch (err) { - assert.equal(err.message.indexOf('Out of range') !== -1, true); - } + + describe('utils', function () { + it('hexlify number', function () { + assert.equal(abi.utils.hexlify(666), '029a'); + assert.equal(abi.utils.hexlify(0), '00'); + assert.equal(abi.utils.hexlify(9007199254740990), '1ffffffffffffe'); + assert.throws(() => abi.utils.hexlify(-1), new Error('invalid hexlify value -1')); + }); + it('hexlify bigint', function () { + assert.equal(abi.utils.hexlify(BigInt(9007199254740991)), '1fffffffffffff'); + assert.equal(abi.utils.hexlify(BigInt('0b11111111111111111111111111111111111111111111111111111')), '1fffffffffffff'); + assert.throws(() => abi.utils.hexlify(-1n), new Error('invalid hexlify value -1')); + }); + it('hexlify string', function () { + assert.equal(abi.utils.hexlify('1fffffffffffff'), '1fffffffffffff'); + assert.throws(() => abi.utils.hexlify('function'), new Error('not hex string function')); + }); + it('hexlify buffer', function () { + assert.equal(abi.utils.hexlify(Buffer.from('function')), '66756e6374696f6e'); + assert.equal(abi.utils.hexlify(new Uint8Array([ 102, 117, 110, 99, 116, 105, 111, 110 ])), '66756e6374696f6e'); + }); + it('arrayify number', function () { + assert.deepEqual(abi.utils.arrayify(666), new Uint8Array([ 2, 154 ])); + assert.deepEqual(abi.utils.arrayify(0), new Uint8Array([0])); + assert.throws(() => abi.utils.arrayify(-1), new Error('invalid arrayify value -1')); + }); + it('arrayify bigint', function () { + assert.deepEqual(abi.utils.arrayify(BigInt(9007199254740991)), new Uint8Array([ 31, 255, 255, 255, 255, 255, 255 ])); + assert.throws(() => abi.utils.arrayify(-1n), new Error('invalid arrayify value -1')); + }); + it('arrayify string', function () { + assert.deepEqual(abi.utils.arrayify('1fffffffffffff'), Buffer.from('1fffffffffffff', 'hex')); + assert.throws(() => abi.utils.arrayify('function'), new Error('not hex string function')); + }); + it('arrayify buffer', function () { + assert.deepEqual(abi.utils.arrayify(new Uint8Array([ 102, 117, 110, 99, 116, 105, 111, 110 ])), Buffer.from('function')); + assert.deepEqual(abi.utils.arrayify(Buffer.from('function')), new Uint8Array([ 102, 117, 110, 99, 116, 105, 111, 110 ])); + }); }); - it('int -19999999999999999999999999999999999999999999999999999999999999', function () { - try { - abi.decodeParameter('int8', 'fffffffffffff38dd0f10627f5529bdb2c52d4846810af0ac000000000000001'); - } catch (err) { - assert.equal(err.message.indexOf('Out of range') !== -1, true); - } + + describe('coder', function () { + it('array', function () { + assert.deepEqual(new ArrayCoder(new StringCoder('_'), 4, undefined).defaultValue(), [ '', '', '', '' ]); + }); + it('tuple', function () { + assert.deepEqual(new TupleCoder([ new AddressCoder('_'), new BytesCoder('_') ], undefined).defaultValue(), + [ 'vite_0000000000000000000000000000000000000000a4f3a0cb58', '' ]); + assert.deepEqual(new TupleCoder([ new GidCoder('group'), new NumberCoder(8, false, 'id') ], 'user').defaultValue(), + { group: '00000000000000000001', id: 0 }); + }); + it('null', function () { + const _coder = new NullCoder(''); + assert.equal(_coder.defaultValue(), null); + assert.equal(_coder.encode(new Writer(), null), 0); + assert.equal(_coder.decode(new Reader(Buffer.alloc(1))), null); + }); }); }); diff --git a/test/packages/accountBlock/utils.js b/test/packages/accountBlock/utils.js index a6346dd7..a01316b9 100644 --- a/test/packages/accountBlock/utils.js +++ b/test/packages/accountBlock/utils.js @@ -322,7 +322,7 @@ describe('decodeContractAccountBlock decodeAccountBlockDataByContract', function for (let i = 0; i < (abi.inputs || []).length; i++) { const item = abi.inputs[i]; it(item.name, function () { - assert.equal(!!decodeRes[item.name], true); + assert.ok(decodeRes[item.name] != null); }); } }); @@ -369,7 +369,7 @@ describe('getTransactionType', function () { }); } it('customTransactionType helloWorld', function () { - const abi = { methodName: 'hello', inputs: [] }; + const abi = { type: 'function', name: 'hello', inputs: [] }; const contractAddress = 'vite_0000000000000000000000000000000000000003f6af7459b9'; const signFunc = encodeFunctionSignature(abi); diff --git a/test/packages/utils.js b/test/packages/utils.js index 3e7e1a46..a1bc207a 100644 --- a/test/packages/utils.js +++ b/test/packages/utils.js @@ -8,99 +8,107 @@ import { const { keyPair, verify, getPublicKey, sign, random } = ed25519; -it('getBytesSize', function () { - assert.equal(40, getBytesSize('是打发发发 水电费是否爽肤水')); - assert.equal(30, getBytesSize('sdjafofaodsfjwo8eifhsnodslkfjs')); - assert.equal(56, getBytesSize('[坏笑]😊🙂🙂😆😅😅')); - assert.equal(32, getBytesSize('[坏笑]😊🙂🙂😆😅😅', 'utf16')); -}); -it('uriStringify', function () { - assert.equal('vite:vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad/echo?amount=1&data=MTIzYWJjZA', uriStringify({ target_address: 'vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad', params: { amount: 1, data: 'MTIzYWJjZA' }, function_name: 'echo' })); - assert.equal('vite:vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad?tti=tti_5649544520544f4b454e6e40&amount=1&data=MTIzYWJjZA', uriStringify({ target_address: 'vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad', params: { tti: 'tti_5649544520544f4b454e6e40', amount: 1, data: 'MTIzYWJjZA' }})); -}); -it('isValidTokenId', function () { - assert.equal(false, isValidTokenId('5649544520544f4b454e')); - assert.equal(true, isValidTokenId('tti_5649544520544f4b454e6e40')); -}); -it('getTokenIdFromOriginalTokenId', function () { - assert.equal('tti_5649544520544f4b454e6e40', getTokenIdFromOriginalTokenId('5649544520544f4b454e')); -}); -it('getOriginalTokenIdFromTokenId', function () { - assert.equal('5649544520544f4b454e', getOriginalTokenIdFromTokenId('tti_5649544520544f4b454e6e40')); -}); -it('isValidSBPName', function () { - assert.equal(true, isValidSBPName('2323_sdsd')); - assert.equal(true, isValidSBPName('2323_sd sd')); - assert.equal(false, isValidSBPName(' 2323_sdsd ')); - assert.equal(false, isValidSBPName('2323_sd sd')); - assert.equal(false, isValidSBPName('232涉及到法律是否啊3_sd sd')); -}); -it('isInteger', function () { - assert.equal(false, isInteger('232 2323')); - assert.equal(true, isInteger('2323')); - assert.equal(true, isInteger('209823')); - assert.equal(false, isInteger('09823')); - assert.equal(false, isInteger('-09823')); - assert.equal(false, isInteger('0000')); - assert.equal(true, isInteger('0')); - assert.equal(false, isInteger('-0')); - assert.equal(true, isInteger('-209823')); - assert.equal(false, isInteger('-2.323')); - assert.equal(false, isInteger('0.23829')); -}); -it('isNonNegativeInteger', function () { - assert.equal(false, isNonNegativeInteger('232 2323')); - assert.equal(true, isNonNegativeInteger('2323')); - assert.equal(false, isNonNegativeInteger('0000')); - assert.equal(true, isNonNegativeInteger('0')); - assert.equal(false, isNonNegativeInteger('0.23829')); -}); -it('isSafeInteger', function () { - assert.equal(-1, isSafeInteger('232 2323')); - assert.equal(1, isSafeInteger('2323')); - assert.equal(1, isSafeInteger(209823)); - assert.equal(-1, isSafeInteger('09823')); - assert.equal(-1, isSafeInteger('-09823')); - assert.equal(-1, isSafeInteger('0000')); - assert.equal(1, isSafeInteger('0')); - assert.equal(-1, isSafeInteger('-0')); - assert.equal(1, isSafeInteger('-209823')); - assert.equal(0, isSafeInteger(-2.323)); - assert.equal(-1, isSafeInteger('0.23829')); - assert.equal(0, isSafeInteger(0.23829)); - assert.equal(0, isSafeInteger(-1000000000000000000)); - assert.equal(0, isSafeInteger(1000000000000000000)); -}); -it('isArray', function () { - assert.equal(false, isArray('2323_sdsd')); - assert.equal(true, isArray([])); - assert.equal(false, isArray({})); - assert.equal(true, isArray(new Array(3))); - assert.equal(false, isArray(new function a() {}())); -}); -it('isObject', function () { - assert.equal(false, isObject('2323_sdsd')); - assert.equal(false, isObject(1)); - assert.equal(true, isObject([])); - assert.equal(true, isObject({})); - assert.equal(true, isObject(new Array(3))); - assert.equal(true, isObject(new function a() {}())); -}); -it('isHexString', function () { - assert.equal(false, isHexString('2323_sdsd')); - assert.equal(true, isHexString(1)); - assert.equal(false, isHexString([])); - assert.equal(true, isHexString('f0fde0110193147e7961e61eeb22576c535b3442fd6bd9c457775e0cc69f1951')); - assert.equal(true, isHexString('3132333435363738393054455354')); -}); -it('isBase64String', function () { - assert.equal(false, isBase64String('2323_sdsd')); - assert.equal(false, isBase64String(1)); - assert.equal(false, isBase64String([])); - assert.equal(true, isBase64String('f0fde0110193147e7961e61eeb22576c535b3442fd6bd9c457775e0cc69f1951')); - assert.equal(false, isBase64String('f0fde0110193147e71e61eeb22576c535b3442fd6bd9c457775e0cc69f1951')); - assert.equal(true, isBase64String('pinFMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB')); +describe('utils', function () { + it('getBytesSize', function () { + assert.equal(40, getBytesSize('是打发发发 水电费是否爽肤水')); + assert.equal(30, getBytesSize('sdjafofaodsfjwo8eifhsnodslkfjs')); + assert.equal(56, getBytesSize('[坏笑]😊🙂🙂😆😅😅')); + assert.equal(32, getBytesSize('[坏笑]😊🙂🙂😆😅😅', 'utf16')); + }); + it('uriStringify', function () { + assert.equal('vite:vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad/echo?amount=1&data=MTIzYWJjZA', uriStringify({ target_address: 'vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad', params: { amount: 1, data: 'MTIzYWJjZA' }, function_name: 'echo' })); + assert.equal('vite:vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad?tti=tti_5649544520544f4b454e6e40&amount=1&data=MTIzYWJjZA', uriStringify({ target_address: 'vite_fa1d81d93bcc36f234f7bccf1403924a0834609f4b2e9856ad', params: { tti: 'tti_5649544520544f4b454e6e40', amount: 1, data: 'MTIzYWJjZA' }})); + }); + it('isValidTokenId', function () { + assert.equal(false, isValidTokenId('5649544520544f4b454e')); + assert.equal(true, isValidTokenId('tti_5649544520544f4b454e6e40')); + assert.equal(true, isValidTokenId('tti_14004f86a14b291f0d7966ae')); + }); + it('getTokenIdFromOriginalTokenId', function () { + assert.equal('tti_5649544520544f4b454e6e40', getTokenIdFromOriginalTokenId('5649544520544f4b454e')); + }); + it('getOriginalTokenIdFromTokenId', function () { + assert.equal('5649544520544f4b454e', getOriginalTokenIdFromTokenId('tti_5649544520544f4b454e6e40')); + }); + it('isValidSBPName', function () { + assert.equal(true, isValidSBPName('2323_sdsd')); + assert.equal(true, isValidSBPName('2323_sd sd')); + assert.equal(false, isValidSBPName(' 2323_sdsd ')); + assert.equal(false, isValidSBPName('2323_sd sd')); + assert.equal(false, isValidSBPName('232涉及到法律是否啊3_sd sd')); + }); + it('isInteger', function () { + assert.equal(false, isInteger('232 2323')); + assert.equal(true, isInteger('2323')); + assert.equal(true, isInteger('209823')); + assert.equal(false, isInteger('09823')); + assert.equal(false, isInteger('-09823')); + assert.equal(false, isInteger('0000')); + assert.equal(true, isInteger('0')); + assert.equal(false, isInteger('-0')); + assert.equal(true, isInteger('-209823')); + assert.equal(false, isInteger('-2.323')); + assert.equal(false, isInteger('0.23829')); + }); + it('isNonNegativeInteger', function () { + assert.equal(false, isNonNegativeInteger('232 2323')); + assert.equal(true, isNonNegativeInteger('2323')); + assert.equal(false, isNonNegativeInteger('0000')); + assert.equal(true, isNonNegativeInteger('0')); + assert.equal(false, isNonNegativeInteger('0.23829')); + }); + it('isSafeInteger', function () { + assert.equal(-1, isSafeInteger('232 2323')); + assert.equal(1, isSafeInteger('2323')); + assert.equal(1, isSafeInteger(209823)); + assert.equal(-1, isSafeInteger('09823')); + assert.equal(-1, isSafeInteger('-09823')); + assert.equal(-1, isSafeInteger('0000')); + assert.equal(1, isSafeInteger('0')); + assert.equal(-1, isSafeInteger('-0')); + assert.equal(1, isSafeInteger('-209823')); + assert.equal(0, isSafeInteger(-2.323)); + assert.equal(-1, isSafeInteger('0.23829')); + assert.equal(0, isSafeInteger(0.23829)); + assert.equal(0, isSafeInteger(-1000000000000000000)); + assert.equal(0, isSafeInteger(1000000000000000000)); + }); + it('isArray', function () { + assert.equal(false, isArray('2323_sdsd')); + assert.equal(true, isArray([])); + assert.equal(false, isArray({})); + assert.equal(true, isArray(new Array(3))); + assert.equal(false, isArray(new function a() {}())); + }); + it('isObject', function () { + assert.equal(false, isObject('2323_sdsd')); + assert.equal(false, isObject(1)); + assert.equal(true, isObject([])); + assert.equal(true, isObject({})); + assert.equal(true, isObject(new Array(3))); + assert.equal(true, isObject(new function a() {}())); + }); + it('isHexString', function () { + assert.equal(false, isHexString('2323_sdsd')); + assert.equal(false, isHexString(1)); + assert.equal(false, isHexString('1', 1)); + assert.equal(false, isHexString([])); + assert.equal(false, isHexString(JSON.stringify({ name: 'alice' }))); + assert.equal(true, isHexString('f0fde0110193147e7961e61eeb22576c535b3442fd6bd9c457775e0cc69f1951')); + assert.equal(true, isHexString('f0fde0110193147e7961e61eeb22576c535b3442fd6bd9c457775e0cc69f1951', 32)); + assert.equal(false, isHexString('0f0fde0110193147e7961e61eeb22576c535b3442fd6bd9c457775e0cc69f1951', 32)); + assert.equal(true, isHexString('3132333435363738393054455354')); + assert.equal(true, isHexString('')); + }); + it('isBase64String', function () { + assert.equal(false, isBase64String('2323_sdsd')); + assert.equal(false, isBase64String(1)); + assert.equal(false, isBase64String([])); + assert.equal(true, isBase64String('f0fde0110193147e7961e61eeb22576c535b3442fd6bd9c457775e0cc69f1951')); + assert.equal(false, isBase64String('f0fde0110193147e71e61eeb22576c535b3442fd6bd9c457775e0cc69f1951')); + assert.equal(true, isBase64String('pinFMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB')); // assert.equal(false, isBase64String('00000500fffffffffeffffffffff005dfb62cb000001')); + }); }); describe('ed25519', function () { diff --git a/test/packages/viteAPI/index.js b/test/packages/viteAPI/index.js index 7c29ec3d..060e42d0 100644 --- a/test/packages/viteAPI/index.js +++ b/test/packages/viteAPI/index.js @@ -17,14 +17,28 @@ it('extends of ViteAPI/Provider', function () { }); describe('ViteAPI addTxType', function () { - const abi = { methodName: 'hello', inputs: [] }; - const contractAddress = 'vite_0000000000000000000000000000000000000003f6af7459b9'; + const contractLists = { + helloWorld: { + contractAddress: 'vite_0000000000000000000000000000000000000003f6af7459b9', + abi: { type: 'function', name: 'hello', inputs: [] } + }, + FullNodeStake: { + contractAddress: 'vite_8cf2663cc949442db2d3f78f372621733292d1fb0b846f1651', + abi: { 'inputs': [], 'name': 'stake', 'outputs': [], 'payable': true, 'type': 'function' } + }, + FullNodeCancelStake: { + contractAddress: 'vite_b3b6335ef23ef3826cff125b81efd158dac3c2209748e0601a', + abi: { 'inputs': [{ 'name': 'id', 'type': 'bytes32' }], 'name': 'cancelStake', 'payable': false, 'type': 'function' } + } + }; - myViteAPI.addTransactionType({ helloWorld: { contractAddress, abi }}); - const signFunc = encodeFunctionSignature(abi); - const key = `${ signFunc }_${ contractAddress }`; + myViteAPI.addTransactionType(contractLists); + for (const name in contractLists) { + const signFunc = encodeFunctionSignature(contractLists[name].abi); + const key = `${ signFunc }_${ contractLists[name].contractAddress }`; - it('isHaveTxType', function () { - assert.equal(myViteAPI.transactionType[key].transactionType, 'helloWorld'); - }); + it('isHaveTxType', function () { + assert.equal(myViteAPI.transactionType[key].transactionType, name); + }); + } });