packages/oo7-substrate/src/ss58.js
- const bs58 = require('bs58')
- const { blake2b } = require('blakejs')
- const { toLE, leToNumber } = require('./utils')
- const { AccountIndex, AccountId } = require('./types')
-
- let defaultType = 42
- const KNOWN_TYPES = [0, 1, 42, 43, 68, 69]
-
- function setNetworkDefault(type) {
- defaultType = type
- }
-
- function ss58Encode(a, type = defaultType, checksumLength = null, length = null, accountId) {
- let payload
- if (KNOWN_TYPES.indexOf(type) === -1) {
- throw new Error('Unknown ss58 address type', type)
- }
- if (typeof a === 'number' || a instanceof AccountIndex) {
- let minLength = (a < (1 << 8) ? 1 : a < (1 << 16) ? 2 : a < (1 << 32) ? 4 : 8)
- length = length ? length : minLength
- if ([1, 2, 4, 8].indexOf(length) === -1) {
- throw new Error('Invalid length')
- }
- length = Math.max(minLength, length)
- if (checksumLength && typeof checksumLength !== 'number') {
- throw new Error('Invalid checksum length')
- }
- switch (length) {
- case 1: { checksumLength = 1; break; }
- case 2: { checksumLength = ([1, 2].indexOf(checksumLength) + 1) || 1; break; }
- case 4: { checksumLength = ([1, 2, 3, 4].indexOf(checksumLength) + 1) || 1; break; }
- case 8: { checksumLength = ([1, 2, 3, 4, 5, 6, 7, 8].indexOf(checksumLength) + 1) || 1; break; }
- }
- payload = toLE(a, length)
- } else if ((a instanceof AccountId || a instanceof Uint8Array) && a.length === 32) {
- checksumLength = 2
- payload = a
- accountId = a
- } else {
- throw new Error('Unknown item to encode as ss58. Passing back.', a)
- }
- let hash = blake2b((type & 1) ? accountId : new Uint8Array([type, ...payload]))
- let complete = new Uint8Array([type, ...payload, ...hash.slice(0, checksumLength)])
- return bs58.encode(Buffer.from(complete))
- }
-
- /// `lookupIndex` must be synchronous. If you can do that, then throw, catch outside the
- /// invocation and then retry once you have the result to hand.
- function ss58Decode(ss58, lookupIndex) {
- let a
- try {
- a = bs58.decode(ss58)
- }
- catch (e) {
- return null
- }
-
- let type = a[0]
- if (KNOWN_TYPES.indexOf(type) === -1) {
- return null
- }
-
- if (a.length < 3) {
- return null
- //throw new Error('Invalid length of payload for address', a.length)
- }
- let length = a.length <= 3
- ? 1
- : a.length <= 5
- ? 2
- : a.length <= 9
- ? 4
- : a.length <= 17
- ? 8
- : 32
- let checksumLength = a.length - 1 - length
-
- let payload = a.slice(1, 1 + length)
- let checksum = a.slice(1 + a.length)
-
- let accountId
- if (length === 32) {
- accountId = payload
- }
-
- let result = length < 32
- ? new AccountIndex(leToNumber(payload))
- : new AccountId(payload)
-
- if (a[0] % 1 && !accountId && !lookupIndex) {
- return null
- }
- let hash = blake2b(a[0] % 1 ? (accountId || lookupIndex(result)) : a.slice(0, 1 + length))
-
- for (var i = 0; i < checksumLength; ++i) {
- if (hash[i] !== a[1 + length + i]) {
- // invalid checksum
- return null
- }
- }
-
- return result
- }
-
- module.exports = { ss58Decode, ss58Encode, setNetworkDefault }