Intelligent constructor (Part 2) (#252)
* Fix AccountId * Fix AccountIndex * Add Bool * Fix Address * Small fixes * Fix Bytes * Fix ExtrinsicSignature * Small fixes * Sorta fix Method * Fix Extrinsic * Fix method * Fix Bytes and KeyValue * Fix Moment * Length-prefix the storage key * Fix Bytes prefix * Add comment
This commit is contained in:
committed by
Jaco Greeff
parent
e409be6dbd
commit
f5948fee52
@@ -53,7 +53,8 @@ describe('methodSend', () => {
|
||||
it('calls the provider with the correct parameters', () => {
|
||||
const method = api.createMethodSend('test_blah', methods.blah);
|
||||
|
||||
return method(new Uint8Array([0x12, 0x34])).then(() => {
|
||||
// Args are length-prefixed, because it's a Bytes
|
||||
return method(new Uint8Array([2 << 2, 0x12, 0x34])).then(() => {
|
||||
expect(provider.send).toHaveBeenCalledWith('test_blah', ['0x1234']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,9 +21,9 @@ describe('fromMetadata', () => {
|
||||
});
|
||||
|
||||
// FIXME check again when we have a valid chain/UI
|
||||
it('should return the correct storage key', () => {
|
||||
it('should return the correct length-prefixed storage key', () => {
|
||||
expect(newStorage.balances.freeBalance('5GwPuAgYgP6q58uWTXp4uSg6FwfzQv9HfFZwAFEREUrQjCvy')).toEqual(
|
||||
Uint8Array.from([52, 103, 23, 10, 157, 95, 244, 9, 70, 215, 120, 149, 1, 238, 109, 69])
|
||||
Uint8Array.from([64, 52, 103, 23, 10, 157, 95, 244, 9, 70, 215, 120, 149, 1, 238, 109, 69])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import Compact, { DEFAULT_LENGTH_BITS } from '@polkadot/types/codec/Compact';
|
||||
import { createType } from '@polkadot/types/codec';
|
||||
import { StorageFunctionMetadata } from '@polkadot/types/Metadata';
|
||||
import { StorageFunction } from '@polkadot/types/StorageKey';
|
||||
@@ -59,13 +60,19 @@ export default function createFunction (
|
||||
|
||||
const type = meta.type.asMap.key.toString(); // Argument type, as string
|
||||
|
||||
return xxhash(
|
||||
const methodAndArgs = xxhash(
|
||||
u8aConcat(
|
||||
u8aFromUtf8(`${section.toString()} ${method.toString()}`),
|
||||
createType(type, arg).toU8a(true)
|
||||
),
|
||||
128
|
||||
);
|
||||
|
||||
// StorageKey is a Bytes, so is length-prefixed
|
||||
return u8aConcat(
|
||||
Compact.encodeU8a(methodAndArgs.length, DEFAULT_LENGTH_BITS),
|
||||
methodAndArgs
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,52 +3,53 @@
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import AccountId from './AccountId';
|
||||
import U8a from './codec/U8a';
|
||||
|
||||
|
||||
const testDecode = (type, input, expected) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const a = new AccountId(input);
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const a = new AccountId('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
expect(a[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
|
||||
describe('AccountId', () => {
|
||||
it('decodes from u8a', () => {
|
||||
expect(
|
||||
new AccountId()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual(
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
});
|
||||
|
||||
it('decodes from address', () => {
|
||||
expect(
|
||||
new AccountId()
|
||||
.fromJSON('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s')
|
||||
.toHex()
|
||||
).toEqual(
|
||||
'0x0102030405060708010203040506070801020304050607080102030405060708'
|
||||
);
|
||||
});
|
||||
testDecode(
|
||||
'AccountId',
|
||||
new AccountId('0x0102030405060708010203040506070801020304050607080102030405060708'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode('hex', '0x0102030405060708010203040506070801020304050607080102030405060708', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testDecode('string', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testDecode(
|
||||
'U8a',
|
||||
new U8a([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array',
|
||||
Uint8Array.from([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
|
||||
it('decodes from hex', () => {
|
||||
expect(
|
||||
new AccountId()
|
||||
.fromJSON('0x0102030405060708010203040506070801020304050607080102030405060708')
|
||||
.toJSON()
|
||||
).toEqual(
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
});
|
||||
|
||||
it('allows creation from another', () => {
|
||||
expect(
|
||||
new AccountId(
|
||||
new AccountId(
|
||||
'0x0102030405060708010203040506070801020304050607080102030405060708'
|
||||
)
|
||||
).toString()
|
||||
).toEqual(
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
});
|
||||
testEncode('toHex', '0x0102030405060708010203040506070801020304050607080102030405060708');
|
||||
testEncode('toJSON', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testEncode('toString', '5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
testEncode('toU8a', Uint8Array.from([
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]));
|
||||
});
|
||||
|
||||
@@ -20,9 +20,7 @@ import U8aFixed from './codec/U8aFixed';
|
||||
export default class AccountId extends U8aFixed {
|
||||
constructor (value: AnyU8a = new Uint8Array()) {
|
||||
super(
|
||||
value instanceof U8a
|
||||
? value.raw
|
||||
: AccountId.decode(value),
|
||||
AccountId.decodeAccountId(value),
|
||||
256
|
||||
);
|
||||
}
|
||||
@@ -31,8 +29,10 @@ export default class AccountId extends U8aFixed {
|
||||
return encodeAddress(value);
|
||||
}
|
||||
|
||||
static decode (value: string | Uint8Array | Array<number>): Uint8Array {
|
||||
if (isU8a(value) || Array.isArray(value)) {
|
||||
static decodeAccountId (value: AnyU8a): Uint8Array {
|
||||
if (value instanceof U8a) {
|
||||
return value.raw;
|
||||
} else if (isU8a(value) || Array.isArray(value)) {
|
||||
return u8aToU8a(value);
|
||||
} else if (isHex(value)) {
|
||||
return hexToU8a(value);
|
||||
@@ -42,7 +42,7 @@ export default class AccountId extends U8aFixed {
|
||||
}
|
||||
|
||||
fromJSON (input: any): AccountId {
|
||||
super.fromJSON(AccountId.decode(input));
|
||||
super.fromJSON(AccountId.decodeAccountId(input));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { AnyU8a } from './types';
|
||||
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aToHex from '@polkadot/util/u8a/toHex';
|
||||
import u8aToU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import { AnyU8a } from './types';
|
||||
import U8a from './codec/U8a';
|
||||
|
||||
// A wrapper around an AccountIndex, which is a shortened, variable-length encoding
|
||||
@@ -15,9 +15,7 @@ import U8a from './codec/U8a';
|
||||
export default class AccountIndex extends U8a {
|
||||
constructor (value: AnyU8a = new Uint8Array()) {
|
||||
super(
|
||||
value instanceof U8a
|
||||
? value.raw
|
||||
: AccountIndex.decode(value)
|
||||
AccountIndex.decodeAccountIndex(value)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,7 +25,15 @@ export default class AccountIndex extends U8a {
|
||||
return u8aToHex(value);
|
||||
}
|
||||
|
||||
static decode (value: string | Uint8Array | Array<number>): Uint8Array {
|
||||
static decodeAccountIndex (value: AnyU8a): Uint8Array {
|
||||
if (value instanceof U8a) {
|
||||
return value.raw;
|
||||
} else if (isU8a(value)) {
|
||||
if (!value.length) {
|
||||
return value;
|
||||
}
|
||||
return value.subarray(0, AccountIndex.readLength(value));
|
||||
}
|
||||
return u8aToU8a(value);
|
||||
}
|
||||
|
||||
@@ -49,7 +55,7 @@ export default class AccountIndex extends U8a {
|
||||
}
|
||||
|
||||
fromJSON (input: any): AccountIndex {
|
||||
super.fromJSON(AccountIndex.decode(input));
|
||||
super.fromJSON(AccountIndex.decodeAccountIndex(input));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2,96 +2,92 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import AccountId from './AccountId';
|
||||
import AccountIndex from './AccountIndex';
|
||||
import Address from './Address';
|
||||
|
||||
const testDecode = (type, input, expected) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const a = new Address(input);
|
||||
expect(a.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const a = new Address('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
expect(a[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
describe('Address', () => {
|
||||
it('decodes with a prefix (255)', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
});
|
||||
testDecode(
|
||||
'Address',
|
||||
new Address('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'AccountId',
|
||||
new AccountId('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'AccountIndex',
|
||||
new AccountIndex('0x0102030405060708010203040506070801020304050607080102030405060708'),
|
||||
'0x0102030405060708010203040506070801020304050607080102030405060708'
|
||||
);
|
||||
testDecode(
|
||||
'Array',
|
||||
[
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
],
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 255)',
|
||||
Uint8Array.from([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
]),
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 1 byte)',
|
||||
Uint8Array.from([17]),
|
||||
'0x11'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 2 bytes)',
|
||||
Uint8Array.from([0xfc, 17, 18]),
|
||||
'0xfc1112'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 4 bytes)',
|
||||
Uint8Array.from([0xfd, 17, 18, 19, 20]),
|
||||
'0xfd11121314'
|
||||
);
|
||||
testDecode(
|
||||
'Uint8Array (with prefix 8 bytes)',
|
||||
Uint8Array.from([0xfe, 17, 18, 19, 20, 21, 22, 23, 24]),
|
||||
'0xfe1112131415161718'
|
||||
);
|
||||
|
||||
it('encodes with a prefix', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromJSON('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s')
|
||||
.toU8a()
|
||||
).toEqual(
|
||||
new Uint8Array([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('encodes address to ss-58 format', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual('5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s');
|
||||
});
|
||||
|
||||
it('decodes with a prefix (1-byte)', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
17
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual('0x11');
|
||||
});
|
||||
|
||||
it('decodes with a prefix (2-bytes)', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
0xfc, 17, 18
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual('0xfc1112');
|
||||
});
|
||||
|
||||
it('decodes with a prefix (4-bytes)', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
0xfd, 17, 18, 19, 20
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual('0xfd11121314');
|
||||
});
|
||||
|
||||
it('decodes with a prefix (8-bytes)', () => {
|
||||
expect(
|
||||
new Address()
|
||||
.fromU8a(
|
||||
new Uint8Array([
|
||||
0xfe, 17, 18, 19, 20, 21, 22, 23, 24
|
||||
])
|
||||
)
|
||||
.toString()
|
||||
).toEqual('0xfe1112131415161718');
|
||||
});
|
||||
// FIXME Add this
|
||||
// testEncode(
|
||||
// 'toHex',
|
||||
// '0x0102030405060708010203040506070801020304050607080102030405060708'
|
||||
// );
|
||||
testEncode(
|
||||
'toString',
|
||||
'5C62W7ELLAAfix9LYrcx5smtcffbhvThkM5x7xfMeYXCt72s'
|
||||
);
|
||||
testEncode(
|
||||
'toU8a',
|
||||
Uint8Array.from([
|
||||
255,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,9 +7,10 @@ import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
import u8aToU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import Base from './codec/Base';
|
||||
import AccountId from './AccountId';
|
||||
import AccountIndex from './AccountIndex';
|
||||
import { AnyU8a } from './types';
|
||||
import Base from './codec/Base';
|
||||
|
||||
const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
|
||||
|
||||
@@ -19,21 +20,26 @@ const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
|
||||
// is encoded as
|
||||
// [ <prefix-byte>, ...publicKey/...bytes ]
|
||||
export default class Address extends Base<AccountId | AccountIndex> {
|
||||
constructor (value: Address | AccountId | AccountIndex | string | Uint8Array = new Uint8Array()) {
|
||||
constructor (value: Address | AccountId | AccountIndex | AnyU8a = new Uint8Array()) {
|
||||
super(
|
||||
value instanceof Address
|
||||
? value.raw
|
||||
: Address.decode(value)
|
||||
Address.decodeAddress(value)
|
||||
);
|
||||
}
|
||||
|
||||
static decode (value: AccountId | AccountIndex | string | Uint8Array | Array<number>): AccountId | AccountIndex {
|
||||
if (value instanceof AccountId || value instanceof AccountIndex) {
|
||||
static decodeAddress (value: Address | AccountId | AccountIndex | AnyU8a): AccountId | AccountIndex {
|
||||
if (value instanceof Address) {
|
||||
return value.raw;
|
||||
} else if (value instanceof AccountId || value instanceof AccountIndex) {
|
||||
return value;
|
||||
} else if (isU8a(value) || Array.isArray(value)) {
|
||||
} else if (Array.isArray(value)) {
|
||||
return Address.decodeAddress(u8aToU8a(value));
|
||||
} else if (isU8a(value)) {
|
||||
if (value.length === 33 && value[0] === 0xff) {
|
||||
return new AccountId(value.subarray(1));
|
||||
}
|
||||
return value.length === 32
|
||||
? new AccountId(u8aToU8a(value))
|
||||
: new AccountIndex(u8aToU8a(value));
|
||||
? new AccountId(value)
|
||||
: new AccountIndex(value);
|
||||
} else if (isHex(value)) {
|
||||
return value.length === 66
|
||||
? new AccountId(value)
|
||||
@@ -54,7 +60,7 @@ export default class Address extends Base<AccountId | AccountIndex> {
|
||||
}
|
||||
|
||||
fromJSON (input: any): Address {
|
||||
this.raw = Address.decode(input);
|
||||
this.raw = Address.decodeAddress(input);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,26 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
|
||||
import Base from './codec/Base';
|
||||
|
||||
export default class Bool extends Base<boolean> {
|
||||
constructor (value: Bool | boolean = false) {
|
||||
super(
|
||||
value instanceof Bool
|
||||
? value.raw
|
||||
: value
|
||||
Bool.decodeBool(value)
|
||||
);
|
||||
}
|
||||
|
||||
static decodeBool (value: any): boolean {
|
||||
if (value instanceof Bool) {
|
||||
return value.raw;
|
||||
} else if (isU8a(value)) {
|
||||
return value[0] === 1;
|
||||
}
|
||||
return !!value;
|
||||
}
|
||||
|
||||
byteLength (): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import hexToU8a from '@polkadot/util/hex/toU8a';
|
||||
import isHex from '@polkadot/util/is/hex';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
|
||||
import { AnyU8a } from './types';
|
||||
import Compact, { DEFAULT_LENGTH_BITS } from './codec/Compact';
|
||||
import U8a from './codec/U8a';
|
||||
|
||||
@@ -11,6 +16,32 @@ import U8a from './codec/U8a';
|
||||
// this version allows for length-encoding. (i.e. it is a variable-item codec, the same
|
||||
// as what is found in Text and Vector)
|
||||
export default class Bytes extends U8a {
|
||||
constructor (value: AnyU8a) {
|
||||
super(Bytes.decodeBytes(value));
|
||||
}
|
||||
|
||||
static decodeBytes (value: AnyU8a): Uint8Array {
|
||||
if (value instanceof U8a) {
|
||||
return value.raw;
|
||||
} else if (isHex(value)) {
|
||||
// FIXME We manually add the length prefix for hex for now
|
||||
// https://github.com/paritytech/substrate/issues/889
|
||||
// Instead of the block below, it should simply be:
|
||||
// return Bytes.decodeBytes(hexToU8a(value as string));
|
||||
const u8a = hexToU8a(value as string);
|
||||
return Bytes.decodeBytes(
|
||||
u8aConcat(
|
||||
Compact.encodeU8a(u8a.length, DEFAULT_LENGTH_BITS),
|
||||
u8a
|
||||
)
|
||||
);
|
||||
} else if (isU8a(value)) {
|
||||
const [offset, length] = Compact.decodeU8a(value, DEFAULT_LENGTH_BITS);
|
||||
return value.subarray(offset, offset + length.toNumber());
|
||||
}
|
||||
return Bytes.decodeBytes(toU8a(value));
|
||||
}
|
||||
|
||||
get length (): number {
|
||||
return this.raw.length;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import Extrinsic from './Extrinsic';
|
||||
import Method from './Method';
|
||||
|
||||
describe('Extrinsic', () => {
|
||||
beforeEach(() => {
|
||||
beforeAll(() => {
|
||||
Method.injectExtrinsics(extrinsics);
|
||||
});
|
||||
|
||||
it('decodes a non-signed properly via fromJSON', () => {
|
||||
const extrinsic = new Extrinsic().fromJSON('0x010200ea51b75b00000000');
|
||||
const extrinsic = new Extrinsic('0x010200ea51b75b00000000');
|
||||
|
||||
expect(extrinsic.isSigned).toEqual(false);
|
||||
expect(extrinsic.callIndex).toEqual(new Uint8Array([2, 0]));
|
||||
|
||||
@@ -7,6 +7,7 @@ import { AnyNumber, AnyU8a } from './types';
|
||||
|
||||
import blake2Asu8a from '@polkadot/util-crypto/blake2/asU8a';
|
||||
import hexToU8a from '@polkadot/util/hex/toU8a';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
import u8aToHex from '@polkadot/util/u8a/toHex';
|
||||
|
||||
@@ -16,6 +17,7 @@ import ExtrinsicSignature from './ExtrinsicSignature';
|
||||
import Hash from './Hash';
|
||||
import { FunctionMetadata } from './Metadata';
|
||||
import Method from './Method';
|
||||
import isHex from '@polkadot/util/is/hex';
|
||||
|
||||
type ExtrinsicValue = {
|
||||
method?: Method
|
||||
@@ -33,11 +35,35 @@ type ExtrinsicValue = {
|
||||
* - left as is, to create an inherent
|
||||
*/
|
||||
export default class Extrinsic extends Struct {
|
||||
constructor (value?: ExtrinsicValue) {
|
||||
constructor (value?: ExtrinsicValue | AnyU8a) {
|
||||
super({
|
||||
signature: ExtrinsicSignature,
|
||||
method: Method
|
||||
}, value);
|
||||
}, Extrinsic.decodeExtrinsic(value));
|
||||
}
|
||||
|
||||
static decodeExtrinsic (value?: ExtrinsicValue | AnyU8a): object | Uint8Array {
|
||||
if (!value) {
|
||||
return {};
|
||||
} else if (value instanceof Extrinsic) {
|
||||
return value.raw;
|
||||
} else if (isHex(value)) {
|
||||
// FIXME We manually add the length prefix for hex for now
|
||||
// https://github.com/paritytech/substrate/issues/889
|
||||
// Instead of the block below, it should simply be:
|
||||
// return Extrinsic.decodeExtrinsic(hexToU8a(value as string));
|
||||
const u8a = hexToU8a(value as string);
|
||||
return Extrinsic.decodeExtrinsic(
|
||||
u8aConcat(
|
||||
Compact.encodeU8a(u8a.length, DEFAULT_LENGTH_BITS),
|
||||
u8a
|
||||
)
|
||||
);
|
||||
} else if (isU8a(value)) {
|
||||
const [offset, length] = Compact.decodeU8a(value, DEFAULT_LENGTH_BITS);
|
||||
return value.subarray(offset, offset + length.toNumber());
|
||||
}
|
||||
return value as any;
|
||||
}
|
||||
|
||||
// the actual [sectionIndex, methodIndex] as used
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { KeyringPair } from '@polkadot/util-keyring/types';
|
||||
import { AnyNumber, AnyU8a } from './types';
|
||||
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
|
||||
import Struct from './codec/Struct';
|
||||
@@ -40,7 +41,24 @@ export default class ExtrinsicSignature extends Struct {
|
||||
signature: Signature,
|
||||
nonce: Nonce,
|
||||
era: ExtrinsicEra
|
||||
}, value);
|
||||
}, ExtrinsicSignature.decodeExtrinsicSignature(value));
|
||||
}
|
||||
|
||||
static decodeExtrinsicSignature (value: ExtrinsicSignature | ExtrinsicSignatureValue | AnyU8a | undefined): object | Uint8Array {
|
||||
if (!value) {
|
||||
return {};
|
||||
} else if (value instanceof Struct) {
|
||||
return value.raw;
|
||||
} else if (isU8a(value)) {
|
||||
const version = value[0];
|
||||
|
||||
if ((version & BIT_SIGNED) === BIT_SIGNED) {
|
||||
return value.subarray(1);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return value as any;
|
||||
}
|
||||
|
||||
byteLength (): number {
|
||||
@@ -73,7 +91,7 @@ export default class ExtrinsicSignature extends Struct {
|
||||
}
|
||||
|
||||
get version (): number {
|
||||
// Version Information.
|
||||
// Version Information.
|
||||
// 1 byte: version information:
|
||||
// - 7 low bits: version identifier (should be 0b0000001).
|
||||
// - 1 high bit: signed flag: 1 if this is a transaction (e.g. contains a signature).
|
||||
|
||||
@@ -7,8 +7,8 @@ import KeyValue, { KeyValueOption } from './KeyValue';
|
||||
describe('KeyValue', () => {
|
||||
it('decodes KeyValue from u8a', () => {
|
||||
expect(
|
||||
new KeyValue().fromU8a(
|
||||
new Uint8Array([
|
||||
new KeyValue(
|
||||
Uint8Array.from([
|
||||
4 << 2,
|
||||
0x11, 0x22, 0x33, 0x44,
|
||||
9 << 2,
|
||||
@@ -23,7 +23,7 @@ describe('KeyValue', () => {
|
||||
|
||||
it('encodes KeyValue from JSON', () => {
|
||||
expect(
|
||||
new KeyValue().fromJSON({
|
||||
new KeyValue({
|
||||
key: '0x11223344',
|
||||
value: '0x998877665544332211'
|
||||
}).toU8a()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { AnyU8a } from './types';
|
||||
|
||||
import { ExtrinsicFunction, Extrinsics } from '@polkadot/extrinsics/types';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
|
||||
import createType from './codec/createType';
|
||||
@@ -22,6 +23,7 @@ const extrinsicFns: { [index: string]: ExtrinsicFunction } = {};
|
||||
/**
|
||||
* Extrinsic function descriptor, as defined in
|
||||
* {@link https://github.com/paritytech/wiki/blob/master/Extrinsic.md#the-extrinsic-format-for-node}.
|
||||
* // FIXME This class should extend Struct({ callIndex, method })
|
||||
*/
|
||||
export default class Method extends MethodIndex {
|
||||
protected _args: Array<Base>;
|
||||
@@ -40,6 +42,13 @@ export default class Method extends MethodIndex {
|
||||
}
|
||||
|
||||
this._data = Method.encode(this._meta, this._args);
|
||||
|
||||
// FIXME this is really not clean, we're saying that if the callIndex is
|
||||
// longer than 2 bytes, then we need to decode the rest too.
|
||||
if (isU8a(index) && index.length > 2) {
|
||||
this.fromU8a(index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static decodeMethod (meta: FunctionMetadata, data: Uint8Array): Array<Base> {
|
||||
|
||||
@@ -2,45 +2,30 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
import Moment from './Moment';
|
||||
import U64 from './U64';
|
||||
|
||||
const testDecode = (type, input, expected, toJSON = false) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
expect(new Moment(input)[toJSON ? 'toJSON' : 'toString']()).toBe(expected);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
expect(new Moment(421)[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
describe('Moment', () => {
|
||||
it('constructs via Date', () => {
|
||||
expect(
|
||||
new Moment(
|
||||
new Date(1537968546280)
|
||||
).toString()
|
||||
).toEqual('2018-09-26T13:29:07.000Z');
|
||||
});
|
||||
testDecode('Date', new Date(1537968546280), '2018-09-26T13:29:07.000Z');
|
||||
testDecode('Moment', new Moment(1234), 1234, true);
|
||||
testDecode('number', 1234, 1234, true);
|
||||
testDecode('U64', new U64(69), 69, true);
|
||||
|
||||
it('wraps from another Moment', () => {
|
||||
expect(
|
||||
new Moment(
|
||||
new Moment(1234)
|
||||
).toJSON()
|
||||
).toEqual(1234);
|
||||
});
|
||||
|
||||
it('reads values from JSON', () => {
|
||||
expect(
|
||||
new Moment().fromJSON(42).toNumber()
|
||||
).toEqual(42);
|
||||
});
|
||||
|
||||
it('reads values from u8a', () => {
|
||||
expect(
|
||||
new Moment().fromU8a(
|
||||
new U64(69).toU8a()
|
||||
).toNumber()
|
||||
).toEqual(69);
|
||||
});
|
||||
|
||||
it('creates valid U64 u8a outputs', () => {
|
||||
expect(
|
||||
new U64().fromU8a(
|
||||
new Moment(421).toU8a()
|
||||
).toNumber()
|
||||
).toEqual(421);
|
||||
});
|
||||
testEncode('toBn', new BN(421));
|
||||
testEncode('toJSON', 421);
|
||||
testEncode('toString', '1970-01-01T00:07:01.000Z');
|
||||
testEncode('toNumber', 421);
|
||||
testEncode('toU8a', Uint8Array.from([165, 1, 0, 0, 0, 0, 0, 0]));
|
||||
});
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
import BN from 'bn.js';
|
||||
import bnToBn from '@polkadot/util/bn/toBn';
|
||||
import bnToU8a from '@polkadot/util/bn/toU8a';
|
||||
import isString from '@polkadot/util/is/string';
|
||||
import isU8a from '@polkadot/util/is/u8a';
|
||||
import u8aToBn from '@polkadot/util/u8a/toBn';
|
||||
|
||||
import { AnyNumber } from './types';
|
||||
import Base from './codec/Base';
|
||||
import U64 from './U64';
|
||||
|
||||
const BITLENGTH = 64;
|
||||
|
||||
@@ -19,21 +22,25 @@ const BITLENGTH = 64;
|
||||
export default class Moment extends Base<Date> {
|
||||
constructor (value: Uint8Array | Moment | Date | BN | number = 0) {
|
||||
super(
|
||||
value instanceof Date
|
||||
? new Date(Math.ceil(value.getTime() / 1000) * 1000)
|
||||
: Moment.decode(value)
|
||||
Moment.decodeMoment(value)
|
||||
);
|
||||
}
|
||||
|
||||
static decode (value: Uint8Array | Moment | number | BN): Date {
|
||||
static decodeMoment (value: Moment | Date | AnyNumber): Date {
|
||||
if (value instanceof Moment) {
|
||||
return value.raw;
|
||||
} if (isU8a(value)) {
|
||||
value = u8aToBn(value, true);
|
||||
} else if (value instanceof Date) {
|
||||
return new Date(Math.ceil(value.getTime() / 1000) * 1000);
|
||||
} else if (value instanceof U64) {
|
||||
value = value.toBn();
|
||||
} else if (isU8a(value)) {
|
||||
value = u8aToBn(value.subarray(0, BITLENGTH / 8), true);
|
||||
} else if (isString(value)) {
|
||||
value = new BN(value, 10, 'le');
|
||||
}
|
||||
|
||||
return new Date(
|
||||
bnToBn(value).toNumber() * 1000
|
||||
bnToBn(value as BN).toNumber() * 1000
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,13 +49,13 @@ export default class Moment extends Base<Date> {
|
||||
}
|
||||
|
||||
fromJSON (input: any): Moment {
|
||||
this.raw = Moment.decode(input);
|
||||
this.raw = Moment.decodeMoment(input);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
fromU8a (input: Uint8Array): Moment {
|
||||
this.raw = Moment.decode(
|
||||
this.raw = Moment.decodeMoment(
|
||||
u8aToBn(input.subarray(0, this.byteLength()), true)
|
||||
);
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
import { AnyU8a } from './types';
|
||||
|
||||
import isFunction from '@polkadot/util/is/function';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
|
||||
import U8a from './codec/U8a';
|
||||
import Bytes from './Bytes';
|
||||
import { StorageFunctionMetadata } from './Metadata';
|
||||
|
||||
@@ -25,15 +23,13 @@ export default class StorageKey extends Bytes {
|
||||
private _outputType: string | null;
|
||||
|
||||
constructor (value: AnyU8a | StorageKey | StorageFunction | [StorageFunction, any]) {
|
||||
super(StorageKey.encode(value));
|
||||
super(StorageKey.decodeStorageKey(value));
|
||||
|
||||
this._outputType = StorageKey.getType(value as StorageKey);
|
||||
}
|
||||
|
||||
static encode (value: AnyU8a | StorageKey | StorageFunction | [StorageFunction, any]): Uint8Array {
|
||||
if (value instanceof StorageKey || value instanceof U8a) {
|
||||
return value.raw;
|
||||
} else if (isFunction(value)) {
|
||||
static decodeStorageKey (value: AnyU8a | StorageKey | StorageFunction | [StorageFunction, any]): Uint8Array {
|
||||
if (isFunction(value)) {
|
||||
return value();
|
||||
} else if (Array.isArray(value)) {
|
||||
const [fn, arg] = value;
|
||||
@@ -42,8 +38,7 @@ export default class StorageKey extends Bytes {
|
||||
return fn(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return toU8a(value);
|
||||
return value as Uint8Array;
|
||||
}
|
||||
|
||||
static getType (value: StorageKey | StorageFunction | [StorageFunction, any]): string | null {
|
||||
|
||||
@@ -60,7 +60,7 @@ export default class Struct<
|
||||
|
||||
return Object
|
||||
.keys(Types)
|
||||
.reduce((raw: T, key, index) => {
|
||||
.reduce((raw: T, key) => {
|
||||
if (isU8a(value)) {
|
||||
// @ts-ignore FIXME See below
|
||||
raw[key] = new Types[key](
|
||||
|
||||
@@ -23,10 +23,10 @@ export default class Tuple<
|
||||
V = { [K in keyof S]: any }
|
||||
> extends Struct<S, T, V> {
|
||||
constructor (Types: S, value?: V | AnyU8a, jsonMap?: Map<keyof S, string>) {
|
||||
super(Types, Tuple.decodeU8a(Types, value), jsonMap);
|
||||
super(Types, Tuple.decodeTuple(Types, value), jsonMap);
|
||||
}
|
||||
|
||||
static decodeU8a<S, V> (Types: S, _value: V | AnyU8a): V {
|
||||
static decodeTuple<S, V> (Types: S, _value: V | AnyU8a): V {
|
||||
if (!isU8a(_value) && !isString(_value) && !Array.isArray(_value)) {
|
||||
return _value as V;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user