@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
106 lines (101 loc) • 4.5 kB
JavaScript
import { Buffer as _Buffer } from "buffer";
import bs58 from 'bs58';
// js extension is required for mjs build, not importing the whole package to reduce bundle size
// eslint-disable-next-line import/extensions
import Sha256 from 'sha.js/sha256.js';
import { DecodeError, ArgumentError, InvalidChecksumError, PayloadLengthError } from './errors.js';
import { concatBuffers, isKeyOfObject } from './other.js';
import * as Encoded from './encoder-types.js';
import { Encoding } from './encoder-types.js';
export { Encoded, Encoding };
/**
* Calculate SHA256 hash of `input`
* @param input - Data to hash
* @returns Hash
*/
export function sha256hash(input) {
return new Sha256().update(input).digest();
}
/**
* @see {@link https://github.com/aeternity/aeserialization/blob/eb68fe331bd476910394966b7f5ede7a74d37e35/src/aeser_api_encoder.erl#L177-L202}
*/
const base64Types = [Encoding.ContractBytearray, Encoding.ContractStoreKey, Encoding.ContractStoreValue, Encoding.Transaction, Encoding.OracleQuery, Encoding.OracleResponse, Encoding.State, Encoding.Poi, Encoding.StateTrees, Encoding.CallStateTree, Encoding.Bytearray];
const base58Types = [Encoding.KeyBlockHash, Encoding.MicroBlockHash, Encoding.BlockPofHash, Encoding.BlockTxHash, Encoding.BlockStateHash, Encoding.Channel, Encoding.ContractAddress, Encoding.TxHash, Encoding.OracleAddress, Encoding.OracleQueryId, Encoding.AccountAddress, Encoding.AccountSecretKey, Encoding.Signature, Encoding.Commitment, Encoding.PeerPubkey, Encoding.Name];
/**
* @see {@link https://github.com/aeternity/aeserialization/blob/eb68fe331bd476910394966b7f5ede7a74d37e35/src/aeser_api_encoder.erl#L261-L286}
*/
const byteSizeForType = {
[Encoding.KeyBlockHash]: 32,
[Encoding.MicroBlockHash]: 32,
[Encoding.BlockPofHash]: 32,
[Encoding.BlockTxHash]: 32,
[Encoding.BlockStateHash]: 32,
[Encoding.Channel]: 32,
[Encoding.ContractAddress]: 32,
[Encoding.TxHash]: 32,
[Encoding.OracleAddress]: 32,
[Encoding.OracleQueryId]: 32,
[Encoding.AccountAddress]: 32,
[Encoding.AccountSecretKey]: 32,
[Encoding.Signature]: 64,
[Encoding.Commitment]: 32,
[Encoding.PeerPubkey]: 32,
[Encoding.State]: 32
};
function ensureValidLength(data, type) {
if (!isKeyOfObject(type, byteSizeForType)) return;
const reqLen = byteSizeForType[type];
if (reqLen == null || data.length === reqLen) return;
throw new PayloadLengthError(`Payload should be ${reqLen} bytes, got ${data.length} instead`);
}
const getChecksum = payload => sha256hash(sha256hash(payload)).slice(0, 4);
const addChecksum = payload => concatBuffers([payload, getChecksum(payload)]);
function getPayload(buffer) {
const payload = buffer.slice(0, -4);
if (!getChecksum(payload).equals(buffer.slice(-4))) throw new InvalidChecksumError();
return payload;
}
const base64 = {
encode: buffer => addChecksum(buffer).toString('base64'),
decode: string => getPayload(_Buffer.from(string, 'base64'))
};
const base58 = {
encode: buffer => bs58.encode(addChecksum(buffer)),
decode: string => getPayload(_Buffer.from(bs58.decode(string)))
};
const parseType = maybeType => {
const base64Type = base64Types.find(t => t === maybeType);
if (base64Type != null) return [base64Type, base64];
const base58Type = base58Types.find(t => t === maybeType);
if (base58Type != null) return [base58Type, base58];
throw new ArgumentError('prefix', `one of ${[...base58Types, ...base64Types].join(', ')}`, maybeType);
};
/**
* Decode data using the default encoding/decoding algorithm
* @param data - An Base58/64check encoded and prefixed string
* (ex tx_..., sg_..., ak_....)
* @returns Decoded data
* @category utils
*/
export function decode(data) {
const [prefix, encodedPayload, extra] = data.split('_');
if (encodedPayload == null) throw new DecodeError(`Encoded string missing payload: ${data}`);
if (extra != null) throw new DecodeError(`Encoded string have extra parts: ${data}`);
const [type, encoder] = parseType(prefix);
const payload = encoder.decode(encodedPayload);
ensureValidLength(payload, type);
return payload;
}
/**
* Encode data using the default encoding/decoding algorithm
* @param data - An decoded data
* @param type - Prefix of Transaction
* @returns Encoded string Base58check or Base64check data
* @category utils
*/
export function encode(data, type) {
const [, encoder] = parseType(type);
ensureValidLength(data, type);
return `${type}_${encoder.encode(data)}`;
}
//# sourceMappingURL=encoder.js.map