UNPKG

4.24 kBJavaScriptView Raw
1import { AbstractBase } from '@polkadot/types-codec';
2import { isBigInt, isBn, isHex, isNumber, isU8a, u8aConcat, u8aToBn, u8aToHex, u8aToU8a } from '@polkadot/util';
3import { decodeAddress } from '@polkadot/util-crypto';
4import { GenericAccountId } from './AccountId.js';
5import { GenericAccountIndex } from './AccountIndex.js';
6export const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
7/** @internal */
8function decodeString(registry, value) {
9 const decoded = decodeAddress(value);
10 return decoded.length === 32
11 ? registry.createTypeUnsafe('AccountId', [decoded])
12 : registry.createTypeUnsafe('AccountIndex', [u8aToBn(decoded)]);
13}
14/** @internal */
15function decodeU8a(registry, value) {
16 // This allows us to instantiate an address with a raw publicKey. Do this first before
17 // we checking the first byte, otherwise we may split an already-existent valid address
18 if (value.length === 32) {
19 return registry.createTypeUnsafe('AccountId', [value]);
20 }
21 else if (value[0] === 0xff) {
22 return registry.createTypeUnsafe('AccountId', [value.subarray(1)]);
23 }
24 const [offset, length] = GenericAccountIndex.readLength(value);
25 return registry.createTypeUnsafe('AccountIndex', [u8aToBn(value.subarray(offset, offset + length))]);
26}
27/** @internal */
28function decodeAddressOrIndex(registry, value) {
29 return value instanceof GenericLookupSource
30 ? value.inner
31 : value instanceof GenericAccountId || value instanceof GenericAccountIndex
32 ? value
33 : isBn(value) || isNumber(value) || isBigInt(value)
34 ? registry.createTypeUnsafe('AccountIndex', [value])
35 : Array.isArray(value) || isHex(value) || isU8a(value)
36 ? decodeU8a(registry, u8aToU8a(value))
37 : decodeString(registry, value);
38}
39/**
40 * @name LookupSource
41 * @description
42 * A wrapper around an AccountId and/or AccountIndex that is encoded with a prefix.
43 * Since we are dealing with underlying publicKeys (or shorter encoded addresses),
44 * we extend from Base with an AccountId/AccountIndex wrapper. Basically the Address
45 * is encoded as `[ <prefix-byte>, ...publicKey/...bytes ]` as per spec
46 */
47export class GenericLookupSource extends AbstractBase {
48 constructor(registry, value = new Uint8Array()) {
49 super(registry, decodeAddressOrIndex(registry, value));
50 }
51 /**
52 * @description The length of the value when encoded as a Uint8Array
53 */
54 get encodedLength() {
55 const rawLength = this._rawLength;
56 return rawLength + (
57 // for 1 byte AccountIndexes, we are not adding a specific prefix
58 rawLength > 1
59 ? 1
60 : 0);
61 }
62 /**
63 * @description The length of the raw value, either AccountIndex or AccountId
64 */
65 get _rawLength() {
66 return this.inner instanceof GenericAccountIndex
67 ? GenericAccountIndex.calcLength(this.inner)
68 : this.inner.encodedLength;
69 }
70 /**
71 * @description Returns a breakdown of the hex encoding for this Codec
72 */
73 inspect() {
74 const value = this.inner.toU8a().subarray(0, this._rawLength);
75 return {
76 outer: [
77 new Uint8Array(this.inner instanceof GenericAccountIndex
78 ? GenericAccountIndex.writeLength(value)
79 : ACCOUNT_ID_PREFIX),
80 value
81 ]
82 };
83 }
84 /**
85 * @description Returns a hex string representation of the value
86 */
87 toHex() {
88 return u8aToHex(this.toU8a());
89 }
90 /**
91 * @description Returns the base runtime type name for this instance
92 */
93 toRawType() {
94 return 'Address';
95 }
96 /**
97 * @description Encodes the value as a Uint8Array as per the SCALE specifications
98 * @param isBare true when the value has none of the type-specific prefixes (internal)
99 */
100 toU8a(isBare) {
101 const encoded = this.inner.toU8a().subarray(0, this._rawLength);
102 return isBare
103 ? encoded
104 : u8aConcat(this.inner instanceof GenericAccountIndex
105 ? GenericAccountIndex.writeLength(encoded)
106 : ACCOUNT_ID_PREFIX, encoded);
107 }
108}