Use asLatest in metadata extraction (#2800)

* User asLatest in metadata extraction

* Cleanup Decorated, bump

* linting

* cleanup decorate

* Remove registry arg from Decorated
This commit is contained in:
Jaco Greeff
2020-10-29 09:05:53 +01:00
committed by GitHub
parent 524885e8de
commit 600666de1c
32 changed files with 228 additions and 1632 deletions
+1 -1
View File
@@ -30,7 +30,7 @@
"@polkadot/api": "^2.4.2-9",
"@polkadot/rpc-core": "^2.4.2-9",
"@polkadot/types": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"bn.js": "^5.1.3",
"rxjs": "^6.6.3"
}
+3 -3
View File
@@ -32,13 +32,13 @@
"@polkadot/rpc-core": "^2.4.2-9",
"@polkadot/rpc-provider": "^2.4.2-9",
"@polkadot/types": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util-crypto": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"@polkadot/util-crypto": "^3.6.2-8",
"bn.js": "^5.1.3",
"memoizee": "^0.4.14",
"rxjs": "^6.6.3"
},
"devDependencies": {
"@polkadot/keyring": "^3.6.2-7"
"@polkadot/keyring": "^3.6.2-8"
}
}
+4 -4
View File
@@ -28,19 +28,19 @@
"dependencies": {
"@babel/runtime": "^7.12.1",
"@polkadot/api-derive": "^2.4.2-9",
"@polkadot/keyring": "^3.6.2-7",
"@polkadot/keyring": "^3.6.2-8",
"@polkadot/metadata": "^2.4.2-9",
"@polkadot/rpc-core": "^2.4.2-9",
"@polkadot/rpc-provider": "^2.4.2-9",
"@polkadot/types": "^2.4.2-9",
"@polkadot/types-known": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util-crypto": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"@polkadot/util-crypto": "^3.6.2-8",
"bn.js": "^5.1.3",
"eventemitter3": "^4.0.7",
"rxjs": "^6.6.3"
},
"devDependencies": {
"@polkadot/keyring": "^3.6.2-7"
"@polkadot/keyring": "^3.6.2-8"
}
}
+14 -14
View File
@@ -1,10 +1,10 @@
// Copyright 2017-2020 @polkadot/api authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { Constants, Storage } from '@polkadot/metadata/Decorated/types';
import { Constants } from '@polkadot/metadata/Decorated/types';
import { RpcInterface } from '@polkadot/rpc-core/types';
import { Call, Hash, RuntimeVersion } from '@polkadot/types/interfaces';
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, InterfaceTypes, ModulesWithCalls, Registry, RegistryTypes } from '@polkadot/types/types';
import { AnyFunction, CallFunction, Codec, CodecArg as Arg, InterfaceTypes, Registry, RegistryTypes } from '@polkadot/types/types';
import { SubmittableExtrinsic } from '../submittable/types';
import { ApiInterfaceRx, ApiOptions, ApiTypes, DecorateMethod, DecoratedRpc, DecoratedRpcSection, PaginationOptions, QueryableConsts, QueryableModuleStorage, QueryableStorage, QueryableStorageEntry, QueryableStorageMulti, QueryableStorageMultiArg, SubmittableExtrinsicFunction, SubmittableExtrinsics, SubmittableModuleExtrinsics } from '../types';
@@ -171,23 +171,23 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
return this._rpcCore.provider.hasSubscriptions;
}
public injectMetadata (metadata: Metadata, fromEmpty?: boolean, registry?: Registry): void {
const decoratedMeta = new DecoratedMeta(registry || this.#registry, metadata);
public injectMetadata (metadata: Metadata, fromEmpty?: boolean): void {
const decoratedMeta = new DecoratedMeta(metadata);
if (fromEmpty || !this._extrinsics) {
this._extrinsics = this._decorateExtrinsics(decoratedMeta.tx, this._decorateMethod);
this._rx.tx = this._decorateExtrinsics(decoratedMeta.tx, this._rxDecorateMethod);
this._extrinsics = this._decorateExtrinsics(decoratedMeta, this._decorateMethod);
this._rx.tx = this._decorateExtrinsics(decoratedMeta, this._rxDecorateMethod);
} else {
augmentObject('tx', this._decorateExtrinsics(decoratedMeta.tx, this._decorateMethod), this._extrinsics, false);
augmentObject(null, this._decorateExtrinsics(decoratedMeta.tx, this._rxDecorateMethod), this._rx.tx, false);
augmentObject('tx', this._decorateExtrinsics(decoratedMeta, this._decorateMethod), this._extrinsics, false);
augmentObject(null, this._decorateExtrinsics(decoratedMeta, this._rxDecorateMethod), this._rx.tx, false);
}
// this API
augmentObject('query', this._decorateStorage(decoratedMeta.query, this._decorateMethod), this._query, fromEmpty);
augmentObject('query', this._decorateStorage(decoratedMeta, this._decorateMethod), this._query, fromEmpty);
augmentObject('consts', decoratedMeta.consts, this._consts, fromEmpty);
// rx
augmentObject(null, this._decorateStorage(decoratedMeta.query, this._rxDecorateMethod), this._rx.query, fromEmpty);
augmentObject(null, this._decorateStorage(decoratedMeta, this._rxDecorateMethod), this._rx.query, fromEmpty);
augmentObject(null, decoratedMeta.consts, this._rx.consts, fromEmpty);
}
@@ -296,10 +296,10 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
: [arg.creator] as any)));
}
protected _decorateExtrinsics<ApiType extends ApiTypes> (extrinsics: ModulesWithCalls, decorateMethod: DecorateMethod<ApiType>): SubmittableExtrinsics<ApiType> {
protected _decorateExtrinsics<ApiType extends ApiTypes> ({ tx }: DecoratedMeta, decorateMethod: DecorateMethod<ApiType>): SubmittableExtrinsics<ApiType> {
const creator = createSubmittable(this._type, this._rx, decorateMethod);
return Object.entries(extrinsics).reduce((out, [name, section]): SubmittableExtrinsics<ApiType> => {
return Object.entries(tx).reduce((out, [name, section]): SubmittableExtrinsics<ApiType> => {
out[name] = Object.entries(section).reduce((out, [name, method]): SubmittableModuleExtrinsics<ApiType> => {
out[name] = this._decorateExtrinsicEntry(method, creator);
@@ -318,8 +318,8 @@ export default abstract class Decorate<ApiType extends ApiTypes> extends Events
return this._decorateFunctionMeta(method as any, decorated as any) as unknown as SubmittableExtrinsicFunction<ApiType>;
}
protected _decorateStorage<ApiType extends ApiTypes> (storage: Storage, decorateMethod: DecorateMethod<ApiType>): QueryableStorage<ApiType> {
return Object.entries(storage).reduce((out, [name, section]): QueryableStorage<ApiType> => {
protected _decorateStorage<ApiType extends ApiTypes> ({ query }: DecoratedMeta, decorateMethod: DecorateMethod<ApiType>): QueryableStorage<ApiType> {
return Object.entries(query).reduce((out, [name, section]): QueryableStorage<ApiType> => {
out[name] = Object.entries(section).reduce((out, [name, method]): QueryableModuleStorage<ApiType> => {
out[name] = this._decorateStorageEntry(method, decorateMethod);
+2 -2
View File
@@ -204,7 +204,7 @@ export default abstract class Init<ApiType extends ApiTypes> extends Decorate<Ap
this._rx.runtimeVersion = version;
// update the default registry version
const thisRegistry = this.#registries.find(({ isDefault }) => isDefault);
const thisRegistry = this.#registries.find(({ registry }) => registry === metadata.registry);
assert(thisRegistry, 'Initialization error, cannot find the default registry');
@@ -216,7 +216,7 @@ export default abstract class Init<ApiType extends ApiTypes> extends Decorate<Ap
// clear the registry types to ensure that we override correctly
this._initRegistry(thisRegistry.registry.init(), this._runtimeChain as Text, version);
this.injectMetadata(metadata, false, thisRegistry.registry);
this.injectMetadata(metadata, false);
return true;
})
+1 -1
View File
@@ -17,7 +17,7 @@ describe('extractStorageArgs', (): void => {
beforeEach((): void => {
const metadata = new Metadata(registry, metaStatic);
storage = storageFromMeta(registry, metadata);
storage = storageFromMeta(registry, metadata.asLatest);
});
it('validates no-arg plain', (): void => {
+3 -3
View File
@@ -29,11 +29,11 @@
"@babel/runtime": "^7.12.1",
"@polkadot/types": "^2.4.2-9",
"@polkadot/types-known": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util-crypto": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"@polkadot/util-crypto": "^3.6.2-8",
"bn.js": "^5.1.3"
},
"devDependencies": {
"@polkadot/keyring": "^3.6.2-7"
"@polkadot/keyring": "^3.6.2-8"
}
}
@@ -13,7 +13,7 @@ const metadata = new Metadata(registry, json);
registry.setMetadata(metadata);
const decorated = new Decorated(registry, metadata);
const decorated = new Decorated(metadata);
describe('Decorated', () => {
it('should correctly get Alice\'s nonce storage key (u8a)', (): void => {
+6 -11
View File
@@ -1,7 +1,7 @@
// Copyright 2017-2020 @polkadot/metadata authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { ModulesWithCalls, Registry } from '@polkadot/types/types';
import { ModulesWithCalls } from '@polkadot/types/types';
import { Constants, Storage } from './types';
import { assert } from '@polkadot/util';
@@ -19,23 +19,18 @@ import storageFromMeta from './storage/fromMetadata';
export default class Decorated {
public readonly consts: Constants;
public readonly metadata: Metadata;
public readonly registry: Registry;
public readonly query: Storage;
public readonly tx: ModulesWithCalls;
constructor (registry: Registry, value: Metadata) {
constructor (value: Metadata) {
assert(value instanceof Metadata, 'You need to pass a valid Metadata instance to Decorated');
this.registry = registry;
this.metadata = value;
const latest = value.asLatest;
// decoration
this.tx = extrinsicsFromMeta(registry, this.metadata);
this.query = storageFromMeta(registry, this.metadata);
this.consts = constantsFromMeta(registry, this.metadata);
this.tx = extrinsicsFromMeta(value.registry, latest);
this.query = storageFromMeta(value.registry, latest);
this.consts = constantsFromMeta(value.registry, latest);
}
}
@@ -15,7 +15,7 @@ function init (meta: string): [Constants, TypeRegistry] {
registry.setMetadata(metadata);
return [fromMetadata(registry, metadata), registry];
return [fromMetadata(registry, metadata.asLatest), registry];
}
describe('fromMetadata', (): void => {
@@ -1,17 +1,16 @@
// Copyright 2017-2020 @polkadot/metadata authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { MetadataLatest } from '@polkadot/types/interfaces';
import { Registry } from '@polkadot/types/types';
import { Constants, ConstantCodec, ModuleConstants } from '../../types';
import { createTypeUnsafe } from '@polkadot/types/create';
import { hexToU8a, stringCamelCase } from '@polkadot/util';
import Metadata from '../../../Metadata';
/** @internal */
export default function fromMetadata (registry: Registry, metadata: Metadata): Constants {
return metadata.asLatest.modules.reduce((result: Constants, moduleMetadata): Constants => {
export default function fromMetadata (registry: Registry, { modules }: MetadataLatest): Constants {
return modules.reduce((result: Constants, moduleMetadata): Constants => {
if (moduleMetadata.constants.isEmpty) {
return result;
}
@@ -12,7 +12,7 @@ const metadata = new Metadata(registry, json);
registry.setMetadata(metadata);
const newExtrinsics = fromMetadata(registry, metadata);
const newExtrinsics = fromMetadata(registry, metadata.asLatest);
describe('fromMetadata', (): void => {
it('should throw if an incorrect number of args is supplied', (): void => {
@@ -1,7 +1,7 @@
// Copyright 2017-2020 @polkadot/metadata authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { Calls, ModulesWithCalls, Registry, RegistryMetadata, RegistryMetadataModule } from '@polkadot/types/types';
import { Calls, ModulesWithCalls, Registry, RegistryMetadataLatest, RegistryMetadataModule } from '@polkadot/types/types';
import { stringCamelCase } from '@polkadot/util';
@@ -9,8 +9,7 @@ import extrinsics from '../';
import createUnchecked from './createUnchecked';
/** @internal */
export default function fromMetadata (registry: Registry, metadata: RegistryMetadata): ModulesWithCalls {
const modules = metadata.asLatest.modules;
export default function fromMetadata (registry: Registry, { modules }: RegistryMetadataLatest): ModulesWithCalls {
const isIndexed = modules.some(({ index }) => !index.eqn(255));
return modules
@@ -14,7 +14,7 @@ const metadata = new Metadata(registry, metadataStatic);
registry.setMetadata(metadata);
const extrinsics = fromMetadata(registry, metadata);
const extrinsics = fromMetadata(registry, metadata.asLatest);
describe('extrinsics', (): void => {
it('encodes an actual transfer (actual data)', (): void => {
@@ -27,7 +27,7 @@ describe('createFunction', (): void => {
method: 'NextKeys',
prefix: 'Session',
section: 'session'
}, { metaVersion: 9 });
}, {});
expect(
u8aToHex(
@@ -15,7 +15,6 @@ import getHasher, { HasherFunction } from './getHasher';
export interface CreateItemOptions {
key?: string;
metaVersion: number;
skipHashing?: boolean; // We don't hash the keys defined in ./substrate.ts
}
@@ -18,7 +18,7 @@ describe('fromMetadata', (): void => {
registry.setMetadata(metadata);
const decorated = new Decorated(registry, metadata);
const decorated = new Decorated(metadata);
it('should throw if the storage function expects an argument', (): void => {
expect((): any => decorated.query.balances.account()).toThrowError(/requires one argument/);
@@ -1,18 +1,18 @@
// Copyright 2017-2020 @polkadot/metadata authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { MetadataLatest } from '@polkadot/types/interfaces';
import { Registry } from '@polkadot/types/types';
import { ModuleStorage, Storage } from '../../types';
import { stringCamelCase, stringLowerFirst } from '@polkadot/util';
import Metadata from '../../../Metadata';
import createFunction from './createFunction';
import getStorage from './storage';
/** @internal */
export default function fromMetadata (registry: Registry, metadata: Metadata): Storage {
return metadata.asLatest.modules.reduce((result, moduleMetadata): Storage => {
export default function fromMetadata (registry: Registry, { modules }: MetadataLatest): Storage {
return modules.reduce((result, moduleMetadata): Storage => {
if (moduleMetadata.storage.isNone) {
return result;
}
@@ -31,11 +31,11 @@ export default function fromMetadata (registry: Registry, metadata: Metadata): S
method,
prefix,
section
}, { metaVersion: metadata.version });
}, {});
return newModule;
}, {} as ModuleStorage);
return result;
}, { ...getStorage(registry, metadata.version) });
}, { ...getStorage(registry) });
}
@@ -7,7 +7,7 @@ import getStorage from './storage';
describe('storage', (): void => {
const registry = new TypeRegistry();
const storage = getStorage(registry, 8);
const storage = getStorage(registry);
it('should return well known keys', (): void => {
expect(typeof storage.substrate).toBe('object');
@@ -8,12 +8,12 @@ import { Storage } from '../../types';
import * as substrate from './substrate';
/** @internal */
export default function getStorage (registry: Registry, metaVersion: number): Storage {
export default function getStorage (registry: Registry): Storage {
return {
substrate: Object
.entries(substrate)
.reduce((storage: Record<string, StorageEntry>, [key, fn]): Record<string, StorageEntry> => {
(storage as Record<string, unknown>)[key] = fn(registry, metaVersion);
(storage as Record<string, unknown>)[key] = fn(registry);
return storage;
}, {})
@@ -15,8 +15,8 @@ interface SubstrateMetadata {
// Small helper function to factorize code on this page.
/** @internal */
function createRuntimeFunction (method: string, key: string, { documentation, type }: SubstrateMetadata): (registry: Registry, metaVersion: number) => StorageEntry {
return (registry: Registry, metaVersion: number): StorageEntry =>
function createRuntimeFunction (method: string, key: string, { documentation, type }: SubstrateMetadata): (registry: Registry) => StorageEntry {
return (registry: Registry): StorageEntry =>
createFunction(registry, {
meta: {
documentation: registry.createType('Vec<Text>', [documentation]),
@@ -27,7 +27,7 @@ function createRuntimeFunction (method: string, key: string, { documentation, ty
method,
prefix: 'Substrate',
section: 'substrate'
}, { key, metaVersion, skipHashing: true });
}, { key, skipHashing: true });
}
export const code = createRuntimeFunction('code', ':code', {
+2 -2
View File
@@ -30,11 +30,11 @@
"@polkadot/metadata": "^2.4.2-9",
"@polkadot/rpc-provider": "^2.4.2-9",
"@polkadot/types": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"memoizee": "^0.4.14",
"rxjs": "^6.6.3"
},
"devDependencies": {
"@polkadot/keyring": "^3.6.2-7"
"@polkadot/keyring": "^3.6.2-8"
}
}
+5 -5
View File
@@ -29,15 +29,15 @@
"@babel/runtime": "^7.12.1",
"@polkadot/metadata": "^2.4.2-9",
"@polkadot/types": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util-crypto": "^3.6.2-7",
"@polkadot/x-fetch": "^0.3.5",
"@polkadot/x-ws": "^0.3.5",
"@polkadot/util": "^3.6.2-8",
"@polkadot/util-crypto": "^3.6.2-8",
"@polkadot/x-fetch": "^0.3.6",
"@polkadot/x-ws": "^0.3.6",
"bn.js": "^5.1.3",
"eventemitter3": "^4.0.7"
},
"devDependencies": {
"@polkadot/keyring": "^3.6.2-7",
"@polkadot/keyring": "^3.6.2-8",
"mock-socket": "^9.0.3",
"nock": "^13.0.4"
}
+1 -1
View File
@@ -174,7 +174,7 @@ export default class Mock implements ProviderInterface {
this.registry.setMetadata(metadata);
const decorated = new Decorated(this.registry, metadata);
const decorated = new Decorated(metadata);
// Do something every 1 seconds
setInterval((): void => {
+1 -1
View File
@@ -40,7 +40,7 @@
"@polkadot/metadata": "^2.4.2-9",
"@polkadot/rpc-provider": "^2.4.2-9",
"@polkadot/types": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"handlebars": "^4.7.6",
"websocket": "^1.0.32",
"yargs": "^16.1.0"
+1 -1
View File
@@ -28,7 +28,7 @@
"dependencies": {
"@babel/runtime": "^7.12.1",
"@polkadot/types": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"bn.js": "^5.1.3"
},
"devDependencies": {
+3 -3
View File
@@ -28,15 +28,15 @@
"dependencies": {
"@babel/runtime": "^7.12.1",
"@polkadot/metadata": "^2.4.2-9",
"@polkadot/util": "^3.6.2-7",
"@polkadot/util-crypto": "^3.6.2-7",
"@polkadot/util": "^3.6.2-8",
"@polkadot/util-crypto": "^3.6.2-8",
"@types/bn.js": "^4.11.6",
"bn.js": "^5.1.3",
"memoizee": "^0.4.14",
"rxjs": "^6.6.3"
},
"devDependencies": {
"@polkadot/keyring": "^3.6.2-7",
"@polkadot/keyring": "^3.6.2-8",
"@types/memoizee": "^0.4.4"
}
}
+11 -11
View File
@@ -4,7 +4,7 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { ChainProperties, DispatchErrorModule, H256 } from '../interfaces/types';
import { CallFunction, Codec, Constructor, InterfaceTypes, RegistryError, RegistryTypes, Registry, RegistryMetadata, RegisteredTypes } from '../types';
import { CallFunction, Codec, Constructor, InterfaceTypes, RegistryError, RegistryTypes, Registry, RegistryMetadata, RegistryMetadataLatest, RegisteredTypes } from '../types';
import extrinsicsFromMeta from '@polkadot/metadata/Decorated/extrinsics/fromMetadata';
import { BN_ZERO, assert, formatBalance, isFunction, isString, isU8a, isUndefined, logger, stringCamelCase, u8aToHex } from '@polkadot/util';
@@ -22,8 +22,7 @@ import { getTypeDef } from './getTypeDef';
const l = logger('registry');
// create error mapping from metadata
function decorateErrors (_: Registry, metadata: RegistryMetadata, metadataErrors: Record<string, RegistryError>): void {
const modules = metadata.asLatest.modules;
function decorateErrors (_: Registry, { modules }: RegistryMetadataLatest, metadataErrors: Record<string, RegistryError>): void {
const isIndexed = modules.some(({ index }) => !index.eqn(255));
// decorate the errors
@@ -47,8 +46,7 @@ function decorateErrors (_: Registry, metadata: RegistryMetadata, metadataErrors
}
// create event classes from metadata
function decorateEvents (registry: Registry, metadata: RegistryMetadata, metadataEvents: Record<string, Constructor<EventData>>): void {
const modules = metadata.asLatest.modules;
function decorateEvents (registry: Registry, { modules }: RegistryMetadataLatest, metadataEvents: Record<string, Constructor<EventData>>): void {
const isIndexed = modules.some(({ index }) => !index.eqn(255));
// decorate the events
@@ -83,7 +81,7 @@ function decorateEvents (registry: Registry, metadata: RegistryMetadata, metadat
}
// create extrinsic mapping from metadata
function decorateExtrinsics (registry: Registry, metadata: RegistryMetadata, metadataCalls: Record<string, CallFunction>): void {
function decorateExtrinsics (registry: Registry, metadata: RegistryMetadataLatest, metadataCalls: Record<string, CallFunction>): void {
const extrinsics = extrinsicsFromMeta(registry, metadata);
// decorate the extrinsics
@@ -365,15 +363,17 @@ export class TypeRegistry implements Registry {
// sets the metadata
public setMetadata (metadata: RegistryMetadata, signedExtensions?: string[]): void {
decorateExtrinsics(this, metadata, this.#metadataCalls);
decorateErrors(this, metadata, this.#metadataErrors);
decorateEvents(this, metadata, this.#metadataEvents);
const latest = metadata.asLatest;
decorateExtrinsics(this, latest, this.#metadataCalls);
decorateErrors(this, latest, this.#metadataErrors);
decorateEvents(this, latest, this.#metadataEvents);
// setup the available extensions
this.setSignedExtensions(
signedExtensions || (
metadata.asLatest.extrinsic.version.gt(BN_ZERO)
? metadata.asLatest.extrinsic.signedExtensions.map((key) => key.toString())
latest.extrinsic.version.gt(BN_ZERO)
? latest.extrinsic.signedExtensions.map((key) => key.toString())
: defaultExtensions
)
);
@@ -12,7 +12,7 @@ import Extrinsic from './Extrinsic';
const registry = new TypeRegistry();
const metadata = new Metadata(registry, rpcMetadata);
const decorated = new Decorated(registry, metadata);
const decorated = new Decorated(metadata);
const keyring = testingPairs({ type: 'ed25519' }, false);
registry.setMetadata(metadata);
@@ -16,7 +16,7 @@ describe('StorageKey', (): void => {
registry.setMetadata(metadata);
const decorated = new Decorated(registry, metadata);
const decorated = new Decorated(metadata);
it('should allow decoding of a DoubleMap key', (): void => {
const key = new StorageKey(registry, '0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01b66ccada06515787c10000000e535263148daaf49be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f');