diff --git a/packages/type-extrinsics/src/utils/createUnchecked.ts b/packages/type-extrinsics/src/utils/createUnchecked.ts
index 8166523c18..4521ba4e2a 100644
--- a/packages/type-extrinsics/src/utils/createUnchecked.ts
+++ b/packages/type-extrinsics/src/utils/createUnchecked.ts
@@ -22,11 +22,7 @@ export default function createDescriptor (
const callIndex = new Uint8Array([index, meta.id.toNumber()]);
let extrinsicFn: any;
- // If the extrinsic function has an argument of type `Origin`, we ignore it
- // FIXME should be `arg.type !== Origin`, but doesn't work...
- const expectedArgs = meta.arguments.filter((arg) =>
- arg.type.toString() !== 'Origin'
- );
+ const expectedArgs = Method.filterOrigin(meta);
extrinsicFn = (...args: any[]): Extrinsic => {
if (expectedArgs.length.valueOf() !== args.length) {
diff --git a/packages/types/src/Extrinsic.spec.js b/packages/types/src/Extrinsic.spec.js
new file mode 100644
index 0000000000..4ee44310db
--- /dev/null
+++ b/packages/types/src/Extrinsic.spec.js
@@ -0,0 +1,15 @@
+// Copyright 2017-2018 @polkadot/types authors & contributors
+// This software may be modified and distributed under the terms
+// of the ISC license. See the LICENSE file for details.
+
+import Extrinsic from './Extrinsic';
+
+describe('Extrinsic', () => {
+ it('decodes a non-signed properly via fromJSON', () => {
+ const extrinsic = new Extrinsic().fromJSON('0x010200ea51b75b00000000');
+
+ expect(extrinsic.isSigned).toEqual(false);
+ expect(extrinsic.callIndex).toEqual(new Uint8Array([2, 0]));
+ expect(extrinsic.data).toEqual(new Uint8Array([234, 81, 183, 91, 0, 0, 0, 0]));
+ });
+});
diff --git a/packages/types/src/Extrinsic.ts b/packages/types/src/Extrinsic.ts
index 3984bae1f1..e669eec077 100644
--- a/packages/types/src/Extrinsic.ts
+++ b/packages/types/src/Extrinsic.ts
@@ -6,6 +6,7 @@ import { KeyringPair } from '@polkadot/util-keyring/types';
import { AnyNumber, AnyU8a } from './types';
import blake2Asu8a from '@polkadot/util-crypto/blake2/asU8a';
+import hexToU8a from '@polkadot/util/hex/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToHex from '@polkadot/util/u8a/toHex';
@@ -42,8 +43,13 @@ export default class Extrinsic extends Struct {
}, value);
}
- get method (): Method {
- return this.raw.method as Method;
+ // the actual [sectionIndex, methodIndex] as used
+ get callIndex (): Uint8Array {
+ return this.method.callIndex;
+ }
+
+ get data (): Uint8Array {
+ return this.method.data;
}
// convernience, encodes the extrinsic and returns the actual hash
@@ -53,6 +59,10 @@ export default class Extrinsic extends Struct {
);
}
+ get isSigned (): boolean {
+ return this.signature.isSigned;
+ }
+
get length (): number {
return this.toU8a(true).length;
}
@@ -61,9 +71,8 @@ export default class Extrinsic extends Struct {
return this.method.meta;
}
- // the actual [sectionIndex, methodIndex] as used
- get callIndex (): Uint8Array {
- return this.method.callIndex;
+ get method (): Method {
+ return this.raw.method as Method;
}
get signature (): ExtrinsicSignature {
@@ -76,6 +85,12 @@ export default class Extrinsic extends Struct {
return length + Compact.encode(length).length;
}
+ fromJSON (input: any): Extrinsic {
+ super.fromU8a(hexToU8a(input));
+
+ return this;
+ }
+
fromU8a (input: Uint8Array): Extrinsic {
const [offset, length] = Compact.decode(input);
@@ -102,7 +117,7 @@ export default class Extrinsic extends Struct {
}
toHex (): string {
- return u8aToHex(this.toU8a());
+ return u8aToHex(this.toU8a(true));
}
toJSON (): any {
diff --git a/packages/types/src/ExtrinsicSignature.ts b/packages/types/src/ExtrinsicSignature.ts
index 1673404d26..0b8b859b8d 100644
--- a/packages/types/src/ExtrinsicSignature.ts
+++ b/packages/types/src/ExtrinsicSignature.ts
@@ -43,6 +43,15 @@ export default class ExtrinsicSignature extends Struct {
}, value);
}
+ byteLength (): number {
+ // version has 1 byte, signature takes the rest
+ return 1 + (
+ this.isSigned
+ ? super.byteLength()
+ : 0
+ );
+ }
+
get isSigned (): boolean {
return this.signature.length !== 0;
}
diff --git a/packages/types/src/Method.ts b/packages/types/src/Method.ts
index cd84cc1cd5..2084c117bb 100644
--- a/packages/types/src/Method.ts
+++ b/packages/types/src/Method.ts
@@ -9,7 +9,7 @@ import u8aConcat from '@polkadot/util/u8a/concat';
import createType from './codec/createType';
import Base from './codec/Base';
import MethodIndex from './MethodIndex';
-import { FunctionMetadata } from './Metadata';
+import { FunctionMetadata, FunctionArgumentMetadata } from './Metadata';
/**
* Extrinsic function descriptor, as defined in
@@ -17,6 +17,7 @@ import { FunctionMetadata } from './Metadata';
*/
export default class Method extends MethodIndex {
protected _args: Array;
+ protected _data: Uint8Array;
protected _meta: FunctionMetadata;
constructor (index: Method | AnyU8a, meta: FunctionMetadata, args: Array) {
@@ -29,35 +30,72 @@ export default class Method extends MethodIndex {
this._args = args;
this._meta = meta;
}
+
+ this._data = Method.encode(this._meta, this._args);
}
- get args () {
+ static decode (meta: FunctionMetadata, data: Uint8Array): Array {
+ let offset = 0;
+
+ return Method.filterOrigin(meta).map(({ type }) => {
+ const base = createType(type).fromU8a(data.subarray(offset));
+
+ offset += base.byteLength();
+
+ return base;
+ });
+ }
+
+ static encode (meta: FunctionMetadata, args: Array): Uint8Array {
+ const encoded = Method.filterOrigin(meta).map(({ type }, index) =>
+ createType(type, args[index]).toU8a()
+ );
+
+ return u8aConcat(...encoded);
+ }
+
+ // If the extrinsic function has an argument of type `Origin`, we ignore it
+ static filterOrigin (meta?: FunctionMetadata): Array {
+ // FIXME should be `arg.type !== Origin`, but doesn't work...
+ return meta
+ ? meta.arguments.filter(({ type }) =>
+ type.toString() !== 'Origin'
+ )
+ : [];
+ }
+
+ byteLength (): number {
+ return super.byteLength() + this.data.length;
+ }
+
+ get args (): Array {
return this._args;
}
- get index () {
+ get data (): Uint8Array {
+ return this._data;
+ }
+
+ get index (): Uint8Array {
return this.raw;
}
- get meta () {
+ get meta (): FunctionMetadata {
return this._meta;
}
- toU8a (isBare?: boolean): Uint8Array {
- // FIXME Even when decoded, we will need access to the meta
- const args = this.meta
- ? this.meta.arguments
- .filter((arg) =>
- arg.type.toString() !== 'Origin'
- )
- .map((argument, index) =>
- createType(argument.type, this.args[index]).toU8a(isBare)
- )
- : [];
+ fromU8a (input: Uint8Array): Method {
+ super.fromU8a(input);
+ this._data = input.subarray(super.byteLength());
+
+ return this;
+ }
+
+ toU8a (isBare?: boolean): Uint8Array {
return u8aConcat(
super.toU8a(isBare),
- ...args
+ this.data
);
}
}
diff --git a/packages/types/src/codec/U8aFixed.ts b/packages/types/src/codec/U8aFixed.ts
index 4598cb112d..9a79b2c044 100644
--- a/packages/types/src/codec/U8aFixed.ts
+++ b/packages/types/src/codec/U8aFixed.ts
@@ -18,27 +18,31 @@ export default class U8aFixed extends U8a {
this._bitLength = bitLength;
- this._trimLength();
+ this._trim();
}
- private _trimLength (): void {
- this.raw = this.raw.subarray(0, this.byteLength());
+ private _trimLength (): number {
+ return this._bitLength / 8;
+ }
+
+ private _trim (): void {
+ this.raw = this.raw.subarray(0, this._trimLength());
}
byteLength (): number {
- return this._bitLength / 8;
+ return this._trimLength();
}
fromJSON (input: any): U8aFixed {
super.fromJSON(input);
- this._trimLength();
+ this._trim();
return this;
}
fromU8a (input: Uint8Array): U8aFixed {
- super.fromU8a(input.subarray(0, this.byteLength()));
+ super.fromU8a(input.subarray(0, this._trimLength()));
return this;
}