UNPKG

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