diff --git a/src/AeSdk.ts b/src/AeSdk.ts index 7883b48a7b..e5061842a6 100644 --- a/src/AeSdk.ts +++ b/src/AeSdk.ts @@ -1,16 +1,18 @@ import AeSdkBase, { Account } from './AeSdkBase'; import AccountBase from './account/Base'; -import { decode, EncodedData } from './utils/encoder'; +import { decode, Encoded } from './utils/encoder'; import { UnavailableAccountError } from './utils/errors'; export default class AeSdk extends AeSdkBase { - accounts: { [key: EncodedData<'ak'>]: AccountBase } = {}; + accounts: { [key: Encoded.AccountAddress]: AccountBase } = {}; - selectedAddress?: EncodedData<'ak'>; + selectedAddress?: Encoded.AccountAddress; - _resolveAccount(account: Account | EncodedData<'ak'> = this.selectedAddress): AccountBase { + _resolveAccount( + account: Account | Encoded.AccountAddress = this.selectedAddress, + ): AccountBase { if (typeof account === 'string') { - const address = account as EncodedData<'ak'>; + const address = account as Encoded.AccountAddress; decode(address); if (this.accounts[address] == null) throw new UnavailableAccountError(account); account = this.accounts[address]; @@ -22,8 +24,8 @@ export default class AeSdk extends AeSdkBase { * Get accounts addresses * @example addresses() */ - addresses(): Array> { - return Object.keys(this.accounts) as Array>; + addresses(): Encoded.AccountAddress[] { + return Object.keys(this.accounts) as Encoded.AccountAddress[]; } /** @@ -44,7 +46,7 @@ export default class AeSdk extends AeSdkBase { * @param address - Address of account to remove * @example removeAccount(address) */ - removeAccount(address: EncodedData<'ak'>): void { + removeAccount(address: Encoded.AccountAddress): void { if (this.accounts[address] == null) { console.warn(`removeAccount: Account for ${address} not available`); return; @@ -58,7 +60,7 @@ export default class AeSdk extends AeSdkBase { * @param address - Address of account to select * @example selectAccount('ak_xxxxxxxx') */ - selectAccount(address: EncodedData<'ak'>): void { + selectAccount(address: Encoded.AccountAddress): void { decode(address); if (this.accounts[address] == null) throw new UnavailableAccountError(address); this.selectedAddress = address; diff --git a/src/AeSdkAepp.ts b/src/AeSdkAepp.ts index ca2064c714..b4857e745f 100644 --- a/src/AeSdkAepp.ts +++ b/src/AeSdkAepp.ts @@ -1,7 +1,7 @@ import AeSdkBase, { Account } from './AeSdkBase'; import AccountBase from './account/Base'; import AccountRpc from './account/Rpc'; -import { decode, EncodedData } from './utils/encoder'; +import { decode, Encoded } from './utils/encoder'; import { Accounts, RPC_VERSION, WalletInfo, Network, WalletApi, AeppApi, } from './aepp-wallet-communication/rpc/types'; @@ -63,7 +63,7 @@ export default class AeSdkAepp extends AeSdkBase { _resolveAccount(account: Account = this.addresses()[0]): AccountBase { if (typeof account === 'string') { - const address = account as EncodedData<'ak'>; + const address = account as Encoded.AccountAddress; decode(address); if (!this.addresses().includes(address)) throw new UnAuthorizedAccountError(address); account = new AccountRpc({ rpcClient: this.rpcClient, address }); @@ -72,12 +72,12 @@ export default class AeSdkAepp extends AeSdkBase { return super._resolveAccount(account); } - addresses(): Array> { + addresses(): Encoded.AccountAddress[] { if (this._accounts == null) return []; const current = Object.keys(this._accounts.current)[0]; return [ ...current != null ? [current] : [], ...Object.keys(this._accounts.connected), - ] as Array>; + ] as Encoded.AccountAddress[]; } /** @@ -142,7 +142,7 @@ export default class AeSdkAepp extends AeSdkBase { * Ask addresses from wallet * @returns Addresses from wallet */ - async askAddresses(): Promise>> { + async askAddresses(): Promise { this._ensureAccountAccess(); return this.rpcClient.request(METHODS.address, undefined); } diff --git a/src/AeSdkBase.ts b/src/AeSdkBase.ts index 8363b8b55e..ed5f936899 100644 --- a/src/AeSdkBase.ts +++ b/src/AeSdkBase.ts @@ -21,7 +21,7 @@ import { NotImplementedError, TypeError, } from './utils/errors'; -import { EncodedData } from './utils/encoder'; +import { Encoded } from './utils/encoder'; import Compiler from './contract/Compiler'; export type Account = Keypair | AccountBase | any; @@ -190,11 +190,11 @@ class AeSdkBase { } // eslint-disable-next-line class-methods-use-this - addresses(): Array> { + addresses(): Encoded.AccountAddress[] { return []; } - async address({ onAccount }: { onAccount?: Account } = {}): Promise> { + async address({ onAccount }: { onAccount?: Account } = {}): Promise { return this._resolveAccount(onAccount).address(); } @@ -206,9 +206,9 @@ class AeSdkBase { } async signTransaction( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, { onAccount, ...options }: { onAccount?: Account } & Parameters[1] = {}, - ): Promise> { + ): Promise { return this._resolveAccount(onAccount) .signTransaction(tx, { ...options, networkId: await this.getNetworkId(options) }); } @@ -263,7 +263,7 @@ class AeSdkBase { async buildTx( txType: TxType, options: Omit>[1], 'onNode'> & { onNode?: Node }, - ): Promise> { + ): Promise { // @ts-expect-error TODO: need to figure out what's wrong here return _buildTx(txType, { ...this._getOptions(), @@ -296,7 +296,11 @@ type MakeOptional = Args extends [infer Head, ...infer Tail] ? Tail extends [] ? Head extends object ? OptionalIfNotRequired<[Omit - & { onNode?: Node; onCompiler?: Compiler; onAccount?: AccountBase | EncodedData<'ak'> | Keypair }]> + & { + onNode?: Node; + onCompiler?: Compiler; + onAccount?: AccountBase | Encoded.AccountAddress | Keypair; + }]> : [Head] : [Head, ...MakeOptional] : never; diff --git a/src/AeSdkWallet.ts b/src/AeSdkWallet.ts index 334f942fd4..0117d7b38c 100644 --- a/src/AeSdkWallet.ts +++ b/src/AeSdkWallet.ts @@ -19,7 +19,7 @@ import { WalletApi, WalletInfo, } from './aepp-wallet-communication/rpc/types'; -import { EncodedData } from './utils/encoder'; +import { Encoded } from './utils/encoder'; import jsonBig from './utils/json-big'; type RpcClientWallet = RpcClient; @@ -34,7 +34,7 @@ type OnSubscription = ( type OnSign = ( clientId: string, params: Parameters[0], origin: string -) => Promise<{ tx?: EncodedData<'tx'>; onAccount?: Account } | undefined> | Promise; +) => Promise<{ tx?: Encoded.Transaction; onAccount?: Account } | undefined> | Promise; type OnDisconnect = ( clientId: string, params: Parameters[0] @@ -135,7 +135,7 @@ export default class AeSdkWallet extends AeSdk { .forEach((client) => client.notify(METHODS.updateAddress, this.getAccounts())); } - selectAccount(address: EncodedData<'ak'>): void { + selectAccount(address: Encoded.AccountAddress): void { super.selectAccount(address); this._pushAccountsToApps(); } diff --git a/src/Node.ts b/src/Node.ts index 3698d10965..b2f2d44400 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -6,7 +6,7 @@ import { } from './utils/autorest'; import { Node as NodeApi, NodeOptionalParams, ErrorModel } from './apis/node'; import { mapObject } from './utils/other'; -import { EncodedData } from './utils/encoder'; +import { Encoded } from './utils/encoder'; import { MissingParamError } from './utils/errors'; /** @@ -53,7 +53,7 @@ export type TransformNodeType = : Property extends NumberPropertyNames ? PreserveOptional : Property extends 'txHash' - ? PreserveOptional, Type[Property]> + ? PreserveOptional : TransformNodeType } : Type; diff --git a/src/account/Base.ts b/src/account/Base.ts index d2046af04d..57c5a64d2b 100644 --- a/src/account/Base.ts +++ b/src/account/Base.ts @@ -16,7 +16,7 @@ */ import { messageToHash, verifyMessage as verifyMessageCrypto, hash } from '../utils/crypto'; import { buildTx } from '../tx/builder'; -import { decode, EncodedData } from '../utils/encoder'; +import { decode, Encoded } from '../utils/encoder'; import { Tag } from '../tx/builder/constants'; import { getNetworkId } from '../Node'; import { concatBuffers } from '../utils/other'; @@ -53,14 +53,14 @@ export default abstract class AccountBase { * @returns Signed transaction */ async signTransaction( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, { innerTx, networkId, ...options }: { innerTx?: boolean; networkId?: string; authData?: Parameters[1]; authFun?: Parameters[2]; } & Omit[3]>, 'onAccount'> = {}, - ): Promise> { + ): Promise { const prefixes = [await this.getNetworkId({ networkId })]; if (innerTx === true) prefixes.push('inner_tx'); const rlpBinaryTx = decode(tx); @@ -120,5 +120,5 @@ export default abstract class AccountBase { * Obtain account address * @returns Public account address */ - abstract address(opt?: object): Promise>; + abstract address(opt?: object): Promise; } diff --git a/src/account/Memory.ts b/src/account/Memory.ts index 48ab3d3f9f..82456e227a 100644 --- a/src/account/Memory.ts +++ b/src/account/Memory.ts @@ -18,13 +18,13 @@ import AccountBase from './Base'; import { sign, isValidKeypair } from '../utils/crypto'; import { isHex } from '../utils/string'; import { ArgumentError, InvalidKeypairError, MissingParamError } from '../utils/errors'; -import { decode, EncodedData } from '../utils/encoder'; +import { decode, Encoded } from '../utils/encoder'; import { createMetaTx } from '../contract/ga'; const secrets = new WeakMap(); export interface Keypair { - publicKey: EncodedData<'ak'>; + publicKey: Encoded.AccountAddress; secretKey: string | Uint8Array; } @@ -42,7 +42,8 @@ export default class AccountMemory extends AccountBase { * @param options.gaId - Address of generalized account */ constructor( - { keypair, gaId, ...options }: { keypair?: Keypair; gaId?: EncodedData<'ak'> } & ConstructorParameters[0], + { keypair, gaId, ...options }: { keypair?: Keypair; gaId?: Encoded.AccountAddress } + & ConstructorParameters[0], ) { super(options); @@ -78,9 +79,9 @@ export default class AccountMemory extends AccountBase { } async signTransaction( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, options: Parameters[1] = {}, - ): Promise> { + ): Promise { if (!this.isGa || options.innerTx === true) return super.signTransaction(tx, options); const { authData, authFun, onCompiler, onNode, @@ -91,7 +92,7 @@ export default class AccountMemory extends AccountBase { return createMetaTx(tx, authData, authFun, { onCompiler, onNode, onAccount: this }); } - async address(): Promise> { + async address(): Promise { return secrets.get(this).publicKey; } } diff --git a/src/account/Rpc.ts b/src/account/Rpc.ts index 14d2983b93..7b4b75abcc 100644 --- a/src/account/Rpc.ts +++ b/src/account/Rpc.ts @@ -1,7 +1,7 @@ import AccountBase from './Base'; import { METHODS } from '../aepp-wallet-communication/schema'; import { NotImplementedError } from '../utils/errors'; -import { EncodedData } from '../utils/encoder'; +import { Encoded } from '../utils/encoder'; /** * Account provided by wallet @@ -13,11 +13,11 @@ import { EncodedData } from '../utils/encoder'; export default class AccountRpc extends AccountBase { _rpcClient: any; - _address: EncodedData<'ak'>; + _address: Encoded.AccountAddress; constructor( - { rpcClient, address, ...options }: - { rpcClient: any; address: EncodedData<'ak'> } & ConstructorParameters[0], + { rpcClient, address, ...options }: { rpcClient: any; address: Encoded.AccountAddress } + & ConstructorParameters[0], ) { super(options); this._rpcClient = rpcClient; @@ -29,7 +29,7 @@ export default class AccountRpc extends AccountBase { throw new NotImplementedError('RAW signing using wallet'); } - async address(): Promise> { + async address(): Promise { return this._address; } @@ -37,9 +37,9 @@ export default class AccountRpc extends AccountBase { * @returns Signed transaction */ async signTransaction( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, { innerTx, networkId }: Parameters[1] = {}, - ): Promise> { + ): Promise { if (innerTx != null) throw new NotImplementedError('innerTx option in AccountRpc'); const res = await this._rpcClient.request(METHODS.sign, { onAccount: this._address, diff --git a/src/aens.ts b/src/aens.ts index 725b53f325..1f1658b267 100644 --- a/src/aens.ts +++ b/src/aens.ts @@ -30,7 +30,7 @@ import { CLIENT_TTL, NAME_TTL, Tag, AensName, } from './tx/builder/constants'; import { ArgumentError } from './utils/errors'; -import { EncodedData } from './utils/encoder'; +import { Encoded } from './utils/encoder'; import { send, SendOptions } from './spend'; import { getName, getHeight } from './chain'; import { _buildTx, BuildTxOptions } from './tx'; @@ -166,7 +166,7 @@ interface AensUpdateOptions extends */ export async function aensTransfer( name: AensName, - account: EncodedData<'ak'>, + account: Encoded.AccountAddress, options: AensTransferOptions, ): ReturnType { const nameTransferTx = await _buildTx(Tag.NameTransferTx, { @@ -210,8 +210,8 @@ export async function aensQuery( & Parameters[2], ): Promise & { - id: EncodedData<'nm'>; - owner: EncodedData<'ak'>; + id: Encoded.Name; + owner: Encoded.AccountAddress; pointers: KeyPointers | NamePointer[]; ttl: number; update: ( @@ -221,7 +221,7 @@ export async function aensQuery( } ) => ReturnType & ReturnType; transfer: ( - account: EncodedData<'ak'>, + account: Encoded.AccountAddress, options?: Parameters[1] ) => ReturnType & ReturnType; revoke: (options?: Omit[1], 'onNode' | 'onCompiler' | 'onAccount'> & { @@ -237,8 +237,8 @@ export async function aensQuery( const nameEntry = await getName(name, opt); return Object.freeze({ ...nameEntry, - id: nameEntry.id as EncodedData<'nm'>, - owner: nameEntry.owner as EncodedData<'ak'>, + id: nameEntry.id as Encoded.Name, + owner: nameEntry.owner as Encoded.AccountAddress, async update(pointers, options) { return { ...await aensUpdate(name, pointers, { ...opt, ...options }), diff --git a/src/aepp-wallet-communication/rpc/types.ts b/src/aepp-wallet-communication/rpc/types.ts index fe7157616a..1a57a42c96 100644 --- a/src/aepp-wallet-communication/rpc/types.ts +++ b/src/aepp-wallet-communication/rpc/types.ts @@ -1,5 +1,5 @@ import { send } from '../../spend'; -import { EncodedData } from '../../utils/encoder'; +import { Encoded } from '../../utils/encoder'; import { METHODS, SUBSCRIPTION_TYPES, WALLET_TYPE } from '../schema'; export interface WalletInfo { @@ -11,8 +11,8 @@ export interface WalletInfo { } export interface Accounts { - connected: { [pub: EncodedData<'ak'>]: {} }; - current: { [pub: EncodedData<'ak'>]: {} }; + connected: { [pub: Encoded.AccountAddress]: {} }; + current: { [pub: Encoded.AccountAddress]: {} }; } export interface Node { @@ -40,21 +40,21 @@ export interface WalletApi { p: { type: SUBSCRIPTION_TYPES; value: 'connected' | 'current' } ) => Promise<{ subscription: Array<'connected' | 'current'>; address: Accounts }>; - [METHODS.address]: () => Promise>>; + [METHODS.address]: () => Promise; [METHODS.sign]: (( - p: { tx: EncodedData<'tx'>; onAccount: EncodedData<'ak'>; returnSigned: boolean } + p: { tx: Encoded.Transaction; onAccount: Encoded.AccountAddress; returnSigned: boolean } ) => Promise<{ /** * @deprecated this is not a hash at all, will be removed later at the same time * as dropping ability to broadcast transaction by wallet */ transactionHash?: Awaited>; - signedTransaction?: EncodedData<'tx'>; + signedTransaction?: Encoded.Transaction; }>); [METHODS.signMessage]: ( - p: { message: string; onAccount: EncodedData<'ak'> } + p: { message: string; onAccount: Encoded.AccountAddress } ) => Promise<{ signature: string }>; } diff --git a/src/aepp-wallet-communication/schema.ts b/src/aepp-wallet-communication/schema.ts index b3cac4d238..4c76c4bbe8 100644 --- a/src/aepp-wallet-communication/schema.ts +++ b/src/aepp-wallet-communication/schema.ts @@ -1,5 +1,5 @@ // eslint-disable-next-line max-classes-per-file -import { EncodedData } from '../utils/encoder'; +import { Encoded } from '../utils/encoder'; import { BaseError, InternalError } from '../utils/errors'; /** @@ -185,7 +185,7 @@ export class RpcPermissionDenyError extends RpcError { code = 11; - constructor(address: EncodedData<'ak'>) { + constructor(address: Encoded.AccountAddress) { super(`You are not subscribed for account ${address}`); this.data = address; this.name = 'RpcPermissionDenyError'; diff --git a/src/chain.ts b/src/chain.ts index 8518169bfa..8697ffa995 100644 --- a/src/chain.ts +++ b/src/chain.ts @@ -29,7 +29,7 @@ import { Account as AccountNode, ByteCode, ContractObject, DryRunResult, DryRunResults, Generation, KeyBlock, MicroBlockHeader, NameEntry, SignedTx, } from './apis/node'; -import { decode, EncodedData } from './utils/encoder'; +import { decode, Encoded, Encoding } from './utils/encoder'; import AccountBase from './account/Base'; /** @@ -53,9 +53,13 @@ export function _getPollInterval( export class InvalidTxError extends TransactionError { validation: ValidatorResult[]; - transaction: EncodedData<'tx'>; + transaction: Encoded.Transaction; - constructor(message: string, validation: ValidatorResult[], transaction: EncodedData<'tx'>) { + constructor( + message: string, + validation: ValidatorResult[], + transaction: Encoded.Transaction, + ) { super(message); this.name = 'InvalidTxError'; this.validation = validation; @@ -83,7 +87,7 @@ export async function getHeight({ onNode }: { onNode: Node }): Promise { * @returns The transaction as it was mined */ export async function poll( - th: EncodedData<'th'>, + th: Encoded.TxHash, { blocks = 10, interval, onNode, ...options }: @@ -132,7 +136,7 @@ export async function awaitHeight( * @returns Current Height */ export async function waitForTxConfirm( - txHash: EncodedData<'th'>, + txHash: Encoded.TxHash, { confirm = 3, onNode, ...options }: { confirm?: number; onNode: Node } & Parameters[1], ): Promise { @@ -162,7 +166,7 @@ export async function waitForTxConfirm( * @returns Transaction details */ export async function sendTransaction( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, { onNode, onAccount, verify = true, waitMined = true, confirm, ...options }: @@ -193,7 +197,7 @@ export async function sendTransaction( const pollResult = await poll(txHash, { onNode, ...options }); const txData = { ...pollResult, - hash: pollResult.hash as EncodedData<'th'>, + hash: pollResult.hash as Encoded.TxHash, rawTx: tx, }; // wait for transaction confirmation @@ -224,8 +228,8 @@ type SendTransactionOptionsType = { } & Parameters[1] & Omit[1], 'confirm'>; interface SendTransactionOptions extends SendTransactionOptionsType {} interface SendTransactionReturnType extends Partial> { - hash: EncodedData<'th'>; - rawTx: EncodedData<'tx'>; + hash: Encoded.TxHash; + rawTx: Encoded.Transaction; confirmationHeight?: number; } @@ -239,9 +243,9 @@ interface SendTransactionReturnType extends Partial> * @param options.onNode - Node to use */ export async function getAccount( - address: EncodedData<'ak' | 'ct'>, + address: Encoded.AccountAddress | Encoded.ContractAddress, { height, hash, onNode }: - { height?: number; hash?: EncodedData<'kh' | 'mh'>; onNode: Node }, + { height?: number; hash?: Encoded.KeyBlockHash | Encoded.MicroBlockHash; onNode: Node }, ): Promise> { if (height != null) return onNode.getAccountByPubkeyAndHeight(address, height); if (hash != null) return onNode.getAccountByPubkeyAndHash(address, hash); @@ -259,7 +263,7 @@ export async function getAccount( * @param options.hash - The block hash on which to obtain the balance for (default: top of chain) */ export async function getBalance( - address: EncodedData<'ak' | 'ct'>, + address: Encoded.AccountAddress | Encoded.ContractAddress, { format = AE_AMOUNT_FORMATS.AETTOS, ...options }: { format?: AE_AMOUNT_FORMATS } & Parameters[1], ): Promise { @@ -290,7 +294,7 @@ export async function getCurrentGeneration( * @returns Generation */ export async function getGeneration( - hashOrHeight: EncodedData<'kh'> | number, + hashOrHeight: Encoded.KeyBlockHash | number, { onNode }: { onNode: Node }, ): Promise> { if (typeof hashOrHeight === 'number') return onNode.getGenerationByHeight(hashOrHeight); @@ -306,7 +310,7 @@ export async function getGeneration( * @returns Transactions */ export async function getMicroBlockTransactions( - hash: EncodedData<'mh'>, + hash: Encoded.MicroBlockHash, { onNode }: { onNode: Node }, ): Promise> { return (await onNode.getMicroBlockTransactionsByHash(hash)).transactions; @@ -321,7 +325,7 @@ export async function getMicroBlockTransactions( * @returns Key Block */ export async function getKeyBlock( - hashOrHeight: EncodedData<'kh'> | number, + hashOrHeight: Encoded.KeyBlockHash | number, { onNode }: { onNode: Node }, ): Promise> { if (typeof hashOrHeight === 'number') return onNode.getKeyBlockByHeight(hashOrHeight); @@ -337,15 +341,15 @@ export async function getKeyBlock( * @returns Micro block header */ export async function getMicroBlockHeader( - hash: EncodedData<'mh'>, + hash: Encoded.MicroBlockHash, { onNode }: { onNode: Node }, ): Promise> { return onNode.getMicroBlockHeaderByHash(hash); } interface TxDryRunArguments { - tx: EncodedData<'tx'>; - accountAddress: EncodedData<'ak'>; + tx: Encoded.Transaction; + accountAddress: Encoded.AccountAddress; top?: number; txEvents?: any; resolve: Function; @@ -394,8 +398,8 @@ async function txDryRunHandler(key: string, onNode: Node): Promise { * @param options.onNode - Node to use */ export async function txDryRun( - tx: EncodedData<'tx'>, - accountAddress: EncodedData<'ak'>, + tx: Encoded.Transaction, + accountAddress: Encoded.AccountAddress, { top, txEvents, combine, onNode, }: @@ -426,7 +430,7 @@ export async function txDryRun( * @param options.onNode - Node to use */ export async function getContractByteCode( - contractId: EncodedData<'ct'>, + contractId: Encoded.ContractAddress, { onNode }: { onNode: Node }, ): Promise> { return onNode.getContractCode(contractId); @@ -440,7 +444,7 @@ export async function getContractByteCode( * @param options.onNode - Node to use */ export async function getContract( - contractId: EncodedData<'ct'>, + contractId: Encoded.ContractAddress, { onNode }: { onNode: Node }, ): Promise> { return onNode.getContract(contractId); @@ -472,18 +476,20 @@ export async function getName( * @param options.onNode - Node to use * @returns Address or AENS name hash */ -export async function resolveName ( - nameOrId: AensName | EncodedData, +export async function resolveName < + Type extends Encoding.AccountAddress | Encoding.ContractAddress, +>( + nameOrId: AensName | Encoded.Generic, key: string, { verify = true, resolveByNode = false, onNode }: { verify?: boolean; resolveByNode?: boolean; onNode: Node }, -): Promise> { +): Promise> { if (isNameValid(nameOrId)) { if (verify || resolveByNode) { const name = await onNode.getNameEntryByName(nameOrId); const pointer = name.pointers.find((p) => p.key === key); if (pointer == null) throw new AensPointerContextError(nameOrId, key); - if (resolveByNode) return pointer.id as EncodedData; + if (resolveByNode) return pointer.id as Encoded.Generic; } return produceNameId(nameOrId); } diff --git a/src/channel/handlers.ts b/src/channel/handlers.ts index 78a462393b..cb137675f3 100644 --- a/src/channel/handlers.ts +++ b/src/channel/handlers.ts @@ -34,7 +34,7 @@ import { SignTx, } from './internal'; import { unpackTx, buildTx } from '../tx/builder'; -import { encode, EncodedData } from '../utils/encoder'; +import { encode, Encoded, Encoding } from '../utils/encoder'; import { IllegalArgumentError, InsufficientBalanceError, @@ -45,11 +45,11 @@ import type Channel from '.'; import { Tag } from '../tx/builder/constants'; export async function appendSignature( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, signFn: SignTx, -): Promise | number | null> { +): Promise { const { signatures, encodedTx } = unpackTx(tx, Tag.SignedTx).tx; - const result = await signFn(encode(encodedTx.rlpEncoded, 'tx')); + const result = await signFn(encode(encodedTx.rlpEncoded, Encoding.Transaction)); if (typeof result === 'string') { const { tx: signedTx } = unpackTx(result, Tag.SignedTx); return buildTx({ diff --git a/src/channel/index.ts b/src/channel/index.ts index f9be3c2224..143483a6a2 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -35,7 +35,7 @@ import { ChannelState, } from './internal'; import { UnknownChannelStateError, ChannelError } from '../utils/errors'; -import { EncodedData } from '../utils/encoder'; +import { Encoded } from '../utils/encoder'; import { ContractCallReturnType } from '../apis/node'; import { pause } from '../utils/other'; @@ -50,9 +50,9 @@ type EventCallback = (...args: any[]) => void; interface CallContractOptions { amount?: number | BigNumber; - callData?: EncodedData<'cb'>; + callData?: Encoded.ContractBytearray; abiVersion?: number; - contract?: EncodedData<'ct'>; + contract?: Encoded.ContractAddress; returnValue?: any; gasUsed?: number | BigNumber; gasPrice?: number | BigNumber; @@ -285,14 +285,14 @@ export default class Channel { * ``` */ async update( - from: EncodedData<'ak'>, - to: EncodedData<'ak'>, + from: Encoded.AccountAddress, + to: Encoded.AccountAddress, amount: number | BigNumber, sign: SignTx, metadata: string[] = [], ): Promise<{ accepted: boolean; - signedTx?: EncodedData<'tx'>; + signedTx?: Encoded.Transaction; errorCode?: number; errorMessage?: string; }> { @@ -343,10 +343,10 @@ export default class Channel { */ async poi( { accounts, contracts }: { - accounts: Array>; - contracts?: Array>; + accounts: Encoded.AccountAddress[]; + contracts?: Encoded.ContractAddress[]; }, - ): Promise> { + ): Promise { return (await call(this, 'channels.get.poi', { accounts, contracts })).poi; } @@ -371,11 +371,13 @@ export default class Channel { * ) * ``` */ - async balances(accounts: Array>): Promise<{ [key: EncodedData<'ak'>]: string }> { + async balances( + accounts: Encoded.AccountAddress[], + ): Promise<{ [key: Encoded.AccountAddress]: string }> { return Object.fromEntries( (await call(this, 'channels.get.balances', { accounts })) .map((item: { - account: EncodedData<'ak'>; + account: Encoded.AccountAddress; balance: string; }) => [item.account, item.balance]), ); @@ -401,7 +403,7 @@ export default class Channel { * }) * ``` */ - async leave(): Promise<{ channelId: string; signedTx: EncodedData<'tx'> }> { + async leave(): Promise<{ channelId: string; signedTx: Encoded.Transaction }> { return new Promise((resolve, reject) => { enqueueAction( this, @@ -431,7 +433,7 @@ export default class Channel { * ).then(tx => console.log('on_chain_tx', tx)) * ``` */ - async shutdown(sign: Function): Promise> { + async shutdown(sign: Function): Promise { return new Promise((resolve, reject) => { enqueueAction( this, @@ -505,7 +507,7 @@ export default class Channel { sign: SignTx, { onOnChainTx, onOwnWithdrawLocked, onWithdrawLocked }: Pick = {}, - ): Promise<{ accepted: boolean; signedTx: EncodedData<'tx'> }> { + ): Promise<{ accepted: boolean; signedTx: Encoded.Transaction }> { return new Promise((resolve, reject) => { enqueueAction( this, @@ -644,14 +646,16 @@ export default class Channel { { code, callData, deposit, vmVersion, abiVersion, }: { - code: EncodedData<'cb'>; - callData: EncodedData<'cb'>; + code: Encoded.ContractBytearray; + callData: Encoded.ContractBytearray; deposit: number | BigNumber; vmVersion: number; abiVersion: number; }, sign: SignTx, - ): Promise<{ accepted: boolean; signedTx: EncodedData<'tx'>; address: EncodedData<'ct'> }> { + ): Promise<{ + accepted: boolean; signedTx: Encoded.Transaction; address: Encoded.ContractAddress; + }> { return new Promise((resolve, reject) => { enqueueAction( this, @@ -724,7 +728,7 @@ export default class Channel { amount, callData, contract, abiVersion, }: CallContractOptions, sign: SignTx, - ): Promise<{ accepted: boolean; signedTx: EncodedData<'tx'> }> { + ): Promise<{ accepted: boolean; signedTx: Encoded.Transaction }> { return new Promise((resolve, reject) => { enqueueAction( this, @@ -783,15 +787,19 @@ export default class Channel { amount, callData, contract, abiVersion, gasLimit = 1000000, gasPrice = MIN_GAS_PRICE, }: { amount: number; - callData: EncodedData<'cb'>; - contract: EncodedData<'ct'>; + callData: Encoded.ContractBytearray; + contract: Encoded.ContractAddress; abiVersion: number; gasLimit?: number; gasPrice?: number; }, sign: SignTx, { onOnChainTx }: Pick = {}, - ): Promise<{ accepted: boolean; signedTx: EncodedData<'tx'>; tx: EncodedData<'tx'> | Uint8Array }> { + ): Promise<{ + accepted: boolean; + signedTx: Encoded.Transaction; + tx: Encoded.Transaction | Uint8Array; + }> { return new Promise((resolve, reject) => { enqueueAction( this, @@ -854,8 +862,8 @@ export default class Channel { amount, callData, contract, abiVersion, }: { amount: number; - callData: EncodedData<'cb'>; - contract: EncodedData<'ct'>; + callData: Encoded.ContractBytearray; + contract: Encoded.ContractAddress; abiVersion: number; }, ): Promise { @@ -890,8 +898,8 @@ export default class Channel { */ async getContractCall( { caller, contract, round }: { - caller: EncodedData<'ak'>; - contract: EncodedData<'ct'>; + caller: Encoded.AccountAddress; + contract: Encoded.ContractAddress; round: number; }, ): Promise<{ @@ -925,7 +933,7 @@ export default class Channel { * ``` */ async getContractState( - contract: EncodedData<'ct'>, + contract: Encoded.ContractAddress, ): Promise<{ contract: Contract; contractState: object }> { const result = await call(this, 'channels.get.contract', { pubkey: contract }); return snakeToPascalObjKeys({ @@ -981,7 +989,10 @@ export default class Channel { * ) * ``` */ - async sendMessage(message: string | object, recipient: EncodedData<'ak'>): Promise { + async sendMessage( + message: string | object, + recipient: Encoded.AccountAddress, + ): Promise { const info = typeof message === 'object' ? JSON.stringify(message) : message; if (this.status() === 'connecting') { await new Promise((resolve) => { diff --git a/src/channel/internal.ts b/src/channel/internal.ts index 452f43ed8a..0fdd17ae5d 100644 --- a/src/channel/internal.ts +++ b/src/channel/internal.ts @@ -21,7 +21,7 @@ import BigNumber from 'bignumber.js'; import type Channel from '.'; import JsonBig from '../utils/json-big'; import { pascalToSnake } from '../utils/string'; -import { EncodedData } from '../utils/encoder'; +import { Encoded } from '../utils/encoder'; import { BaseError, ChannelCallError, ChannelPingTimedOutError, UnknownChannelStateError, } from '../utils/errors'; @@ -31,20 +31,20 @@ interface ChannelAction { action: (channel: Channel, state?: ChannelFsm) => ChannelFsm; } -export type SignTxWithTag = (tag: string, tx: EncodedData<'tx'>, options?: object) => ( - Promise> +export type SignTxWithTag = (tag: string, tx: Encoded.Transaction, options?: object) => ( + Promise ); // TODO: SignTx shouldn't return number or null -export type SignTx = (tx: EncodedData<'tx'>, options?: object) => ( - Promise | number | null> +export type SignTx = (tx: Encoded.Transaction, options?: object) => ( + Promise ); export interface ChannelOptions { existingFsmId?: string; url: string; role: 'initiator' | 'responder'; - initiatorId: EncodedData<'ak'>; - responderId: EncodedData<'ak'>; + initiatorId: Encoded.AccountAddress; + responderId: Encoded.AccountAddress; pushAmount: number; initiatorAmount: BigNumber; responderAmount: BigNumber; @@ -81,7 +81,7 @@ export interface ChannelState { reject: (e: BaseError) => void; sign: SignTx; handler?: ChannelHandler; - onOnChainTx?: (tx: EncodedData<'tx'>) => void; + onOnChainTx?: (tx: Encoded.Transaction) => void; onOwnWithdrawLocked?: () => void; onWithdrawLocked?: () => void; onOwnDepositLocked?: () => void; @@ -125,7 +125,7 @@ const PONG_TIMEOUT_MS = 5000; // TODO: move to Channel instance to avoid is-null checks and for easier debugging export const options = new WeakMap(); export const status = new WeakMap(); -export const state = new WeakMap>(); +export const state = new WeakMap(); const fsm = new WeakMap(); const websockets = new WeakMap(); export const eventEmitters = new WeakMap(); @@ -165,7 +165,7 @@ export function changeStatus(channel: Channel, newStatus: string): void { } } -export function changeState(channel: Channel, newState: EncodedData<'tx'>): void { +export function changeState(channel: Channel, newState: Encoded.Transaction): void { state.set(channel, newState); emit(channel, 'stateChanged', newState); } diff --git a/src/contract/aci.ts b/src/contract/aci.ts index cc697dba76..f6a1c00deb 100644 --- a/src/contract/aci.ts +++ b/src/contract/aci.ts @@ -21,7 +21,7 @@ import { Tag, AensName } from '../tx/builder/constants'; import { buildContractIdByContractTx, unpackTx } from '../tx/builder'; import { _buildTx } from '../tx'; import { send } from '../spend'; -import { decode, EncodedData, EncodingType } from '../utils/encoder'; +import { decode, Encoded } from '../utils/encoder'; import { MissingContractDefError, MissingContractAddressError, @@ -73,7 +73,7 @@ interface Aci extends BaseAci { } interface Event { - address: EncodedData<'ct'>; + address: Encoded.ContractAddress; data: string; topics: Array; } @@ -83,7 +83,7 @@ interface DecodedEvent { args: unknown; contract: { name: string; - address: EncodedData<'ct'>; + address: Encoded.ContractAddress; }; } @@ -94,9 +94,9 @@ export interface ContractInstance { _name: string; calldata: any; source?: string; - bytecode?: EncodedData<'cb'>; + bytecode?: Encoded.ContractBytearray; deployInfo: { - address?: EncodedData<'ct'>; + address?: Encoded.ContractAddress; result?: { callerId: string; callerNonce: string; @@ -108,13 +108,13 @@ export interface ContractInstance { returnType: ContractCallReturnType; returnValue: string; }; - owner?: EncodedData<'ak'>; + owner?: Encoded.AccountAddress; transaction?: string; rawTx?: string; txData?: TxData; }; options: any; - compile: (options?: {}) => Promise>; + compile: (options?: {}) => Promise; _estimateGas: (name: string, params: any[], options: object) => Promise; deploy: (params?: any[], options?: object) => Promise; call: (fn: string, params?: any[], options?: {}) => Promise<{ @@ -123,9 +123,9 @@ export interface ContractInstance { txData: TxData; rawTx: string; result: { - callerId: EncodedData<'ak'>; + callerId: Encoded.AccountAddress; callerNonce: number; - contractId: EncodedData<'ct'>; + contractId: Encoded.ContractAddress; gasPrice: number; gasUsed: number; height: number; @@ -177,9 +177,9 @@ export default async function getContractInstance({ onCompiler: Compiler; onNode: Node; source?: string; - bytecode?: EncodedData<'cb'>; + bytecode?: Encoded.ContractBytearray; aci?: Aci; - contractAddress?: EncodedData<'ct'> | AensName; + contractAddress?: Encoded.ContractAddress | AensName; fileSystem?: Record; validateBytecode?: boolean; [key: string]: any; @@ -195,7 +195,7 @@ export default async function getContractInstance({ contractAddress, 'contract_pubkey', { resolveByNode: true, onNode }, - ) as EncodedData<'ct'>; + ) as Encoded.ContractAddress; } if (contractAddress == null && source == null && bytecode == null) { @@ -250,19 +250,19 @@ export default async function getContractInstance({ * Compile contract * @returns bytecode */ - instance.compile = async (options = {}): Promise> => { + instance.compile = async (options = {}): Promise => { if (instance.bytecode != null) throw new IllegalArgumentError('Contract already compiled'); if (instance.source == null) throw new IllegalArgumentError('Can\'t compile without source code'); instance.bytecode = (await onCompiler.compileContract({ code: instance.source, options: { ...instance.options, ...options }, - })).bytecode as EncodedData<'cb'>; + })).bytecode as Encoded.ContractBytearray; return instance.bytecode; }; const handleCallError = ( { returnType, returnValue }: { returnType: ContractCallReturnType; - returnValue: EncodedData; + returnValue: Encoded.ContractBytearray; }, transaction: string, ): void => { @@ -281,12 +281,12 @@ export default async function getContractInstance({ throw new NodeInvocationError(message, transaction); }; - const sendAndProcess = async (tx: EncodedData<'tx'>, options: any): Promise<{ + const sendAndProcess = async (tx: Encoded.Transaction, options: any): Promise<{ result?: ContractInstance['deployInfo']['result']; hash: TxData['hash']; tx: Awaited>>; txData: TxData; - rawTx: EncodedData<'tx'>; + rawTx: Encoded.Transaction; }> => { options = { ...instance.options, ...options }; const txData = await send(tx, options); @@ -393,7 +393,7 @@ export default async function getContractInstance({ .catch((error: any) => { if (opt.callStatic === true) return DRY_RUN_ACCOUNT.pub; throw error; - }) as EncodedData<'ak'>; + }) as Encoded.AccountAddress; const callData = instance.calldata.encode(instance._name, fn, params); let res: any; @@ -413,7 +413,7 @@ export default async function getContractInstance({ if (callObj == null) throw new UnexpectedTsError(); handleCallError({ returnType: callObj.returnType as ContractCallReturnType, - returnValue: callObj.returnValue as EncodedData, + returnValue: callObj.returnValue as Encoded.ContractBytearray, }, tx); res = { ...dryRunOther, tx: unpackTx(tx), result: callObj }; } else { @@ -444,9 +444,11 @@ export default async function getContractInstance({ * @throws {@link AmbiguousEventDefinitionError} */ function getContractNameByEvent( - address: EncodedData<'ct'>, + address: Encoded.ContractAddress, nameHash: BigInt, - { contractAddressToName }: { contractAddressToName?: { [key: EncodedData<'ct'>]: string } }, + { contractAddressToName }: { + contractAddressToName?: { [key: Encoded.ContractAddress]: string }; + }, ): string { const addressToName = { ...instance.options.contractAddressToName, ...contractAddressToName }; if (addressToName[address] != null) return addressToName[address]; diff --git a/src/contract/ga.ts b/src/contract/ga.ts index d0ed0186a1..0bdcb8314d 100644 --- a/src/contract/ga.ts +++ b/src/contract/ga.ts @@ -28,7 +28,7 @@ import { _buildTx, BuildTxOptions, getVmVersion, prepareTxParams, } from '../tx'; import { hash } from '../utils/crypto'; -import { decode, EncodedData } from '../utils/encoder'; +import { decode, Encoded, Encoding } from '../utils/encoder'; import { IllegalArgumentError, MissingParamError, InvalidAuthDataError } from '../utils/errors'; import { concatBuffers } from '../utils/other'; import AccountBase from '../account/Base'; @@ -46,7 +46,7 @@ import Compiler from './Compiler'; * @returns if account is GA */ export async function isGA( - address: EncodedData<'ak'>, + address: Encoded.AccountAddress, options: Parameters[1], ): Promise { const { contractId } = await getAccount(address, options); @@ -70,10 +70,10 @@ export async function createGeneralizedAccount( onAccount, onCompiler, onNode, ...options }: CreateGeneralizedAccountOptions, ): Promise; - transaction: EncodedData<'th'>; - rawTx: EncodedData<'tx'>; - gaContractId: EncodedData<'ct'>; + owner: Encoded.AccountAddress; + transaction: Encoded.TxHash; + rawTx: Encoded.Transaction; + gaContractId: Encoded.ContractAddress; }>> { const ownerId = await onAccount.address(options); if (await isGA(ownerId, { onNode })) throw new IllegalArgumentError(`Account ${ownerId} is already GA`); @@ -124,10 +124,10 @@ interface CreateGeneralizedAccountOptions extends * @returns Transaction string */ export async function createMetaTx( - rawTransaction: EncodedData<'tx'>, + rawTransaction: Encoded.Transaction, authData: { gasLimit?: number; - callData?: EncodedData<'cb'>; + callData?: Encoded.ContractBytearray; source?: string; args?: any[]; }, @@ -137,10 +137,12 @@ export async function createMetaTx( }: { onAccount: AccountBase; onCompiler: Compiler; onNode: Node } & Parameters[0], -): Promise> { +): Promise { const wrapInEmptySignedTx = ( - tx: EncodedData<'tx'> | Uint8Array | TxUnpacked, - ): BuiltTx => buildTx({ encodedTx: tx, signatures: [] }, Tag.SignedTx); + tx: Encoded.Transaction | Uint8Array | TxUnpacked, + ): BuiltTx => ( + buildTx({ encodedTx: tx, signatures: [] }, Tag.SignedTx) + ); if (Object.keys(authData).length <= 0) throw new MissingParamError('authData is required'); @@ -187,7 +189,7 @@ export async function createMetaTx( * @returns Transaction hash */ export async function buildAuthTxHash( - transaction: EncodedData<'tx'>, + transaction: Encoded.Transaction, { onNode }: { onNode: Node }, ): Promise { const { networkId } = await onNode.getStatus(); diff --git a/src/contract/methods.ts b/src/contract/methods.ts index ce7430da87..ab10bb1c28 100644 --- a/src/contract/methods.ts +++ b/src/contract/methods.ts @@ -25,7 +25,7 @@ import { AensName } from '../tx/builder/constants'; import { produceNameId } from '../tx/builder/helpers'; import { concatBuffers } from '../utils/other'; -import { decode, EncodedData, EncodingType } from '../utils/encoder'; +import { decode, Encoded } from '../utils/encoder'; import AccountBase from '../account/Base'; import Node from '../Node'; @@ -41,7 +41,7 @@ export { default as getContractInstance } from './aci'; * @returns Signature in hex representation */ async function delegateSignatureCommon( - ids: Array>, + ids: Encoded.Any[], { onAccount, onNode, ...opt }: { onAccount: AccountBase; onNode: Node } & Parameters[1], ): Promise { @@ -78,7 +78,7 @@ async function delegateSignatureCommon( * ``` */ export async function createAensDelegationSignature( - contractId: EncodedData<'ct'>, + contractId: Encoded.ContractAddress, opt: Parameters[0] & Parameters[1] & { name?: AensName }, ): Promise { @@ -112,9 +112,9 @@ export async function createAensDelegationSignature( * ``` */ export async function createOracleDelegationSignature( - contractId: EncodedData<'ct'>, + contractId: Encoded.ContractAddress, opt: Parameters[0] & Parameters[1] & - { queryId?: EncodedData<'oq'> }, + { queryId?: Encoded.OracleQueryId }, ): Promise { return delegateSignatureCommon( [opt.queryId ?? await opt.onAccount.address(opt), contractId], diff --git a/src/deprecated/index.ts b/src/deprecated/index.ts index 3b2043ee45..2e6da7aa39 100644 --- a/src/deprecated/index.ts +++ b/src/deprecated/index.ts @@ -5,7 +5,7 @@ import { calculateMinFee as calculateMinFeeInternal } from '../tx/builder/field- import { TxParamsCommon } from '../tx/builder/schema'; import { AE_AMOUNT_FORMATS } from '../utils/amount-formatter'; import { mapObject } from '../utils/other'; -import { EncodingType } from '../utils/encoder'; +import { Encoding } from '../utils/encoder'; export * from './methods'; @@ -155,7 +155,7 @@ export const PREFIX_ID_TAG = { */ export const ID_TAG_PREFIX = mapObject( PREFIX_ID_TAG, - ([key, value]: [EncodingType, number]) => [value, key], + ([key, value]: [Encoding, number]) => [value, key], ); /** diff --git a/src/deprecated/methods.ts b/src/deprecated/methods.ts index 8d4cd4b4b3..61cfdb8227 100644 --- a/src/deprecated/methods.ts +++ b/src/deprecated/methods.ts @@ -1,4 +1,4 @@ -import { EncodedData } from '../utils/encoder'; +import { Encoded } from '../utils/encoder'; import { createMetaTx } from '../contract/ga'; import Node from '../Node'; @@ -7,12 +7,12 @@ import Node from '../Node'; * @hidden */ export async function signUsingGA( - tx: EncodedData<'tx'>, + tx: Encoded.Transaction, { authData, authFun, ...options }: { authData: Parameters[1]; authFun: Parameters[2]; } & Parameters[3], -): Promise> { +): Promise { return createMetaTx(tx, authData, authFun, options); } diff --git a/src/oracle.ts b/src/oracle.ts index 35075c0d11..84cc9a1569 100644 --- a/src/oracle.ts +++ b/src/oracle.ts @@ -37,7 +37,9 @@ import { } from './tx/builder/schema'; import { Tag } from './tx/builder/constants'; import { RequestTimedOutError } from './utils/errors'; -import { decode, encode, EncodedData } from './utils/encoder'; +import { + decode, encode, Encoded, Encoding, +} from './utils/encoder'; import { _getPollInterval } from './chain'; import { _buildTx, BuildTxOptions } from './tx'; import Node from './Node'; @@ -56,7 +58,7 @@ type OracleQueries = Awaited>['orac * @returns Callback to stop polling function */ export function pollForQueries( - oracleId: EncodedData<'ok'>, + oracleId: Encoded.OracleAddress, onQuery: (queries: OracleQueries) => void, { interval, onNode, ...options }: { interval?: number; onNode: Node } & Parameters[1], @@ -94,8 +96,8 @@ export function pollForQueries( * @returns OracleQuery object */ export async function pollForQueryResponse( - oracleId: EncodedData<'ok'>, - queryId: EncodedData<'oq'>, + oracleId: Encoded.OracleAddress, + queryId: Encoded.OracleQueryId, { interval, onNode, ...options }: { interval?: number; onNode: Node } & Parameters[1], ): Promise { @@ -106,7 +108,7 @@ export async function pollForQueryResponse( do { if (height != null) await pause(interval); ({ response, ttl } = await onNode.getOracleQueryByPubkeyAndQueryId(oracleId, queryId)); - const responseBuffer = decode(response as EncodedData<'or'>); + const responseBuffer = decode(response as Encoded.OracleResponse); if (responseBuffer.length > 0) return responseBuffer.toString(); height = await this.getHeight(); } while (ttl >= height); @@ -122,15 +124,15 @@ export async function pollForQueryResponse( * @returns OracleQuery object */ export async function getQueryObject( - oracleId: EncodedData<'ok'>, - queryId: EncodedData<'oq'>, + oracleId: Encoded.OracleAddress, + queryId: Encoded.OracleQueryId, options: RespondToQueryOptions & Parameters[2], ): Promise { const record = await options.onNode.getOracleQueryByPubkeyAndQueryId(oracleId, queryId); return { ...record, - decodedQuery: decode(record.query as EncodedData<'oq'>).toString(), - decodedResponse: decode(record.response as EncodedData<'or'>).toString(), + decodedQuery: decode(record.query as Encoded.OracleQueryId).toString(), + decodedResponse: decode(record.response as Encoded.OracleResponse).toString(), respond: async (response, opt) => ( // eslint-disable-next-line @typescript-eslint/no-use-before-define respondToQuery(oracleId, queryId, response, { ...options, ...opt }) @@ -162,7 +164,7 @@ interface GetQueryObjectReturnType extends Awaited, + oracleId: Encoded.OracleAddress, query: string, options: PostQueryToOracleOptions, ): Promise> & Awaited>> { @@ -210,7 +212,7 @@ interface PostQueryToOracleOptions extends PostQueryToOracleOptionsType {} * @returns Oracle object */ export async function extendOracleTtl( - oracleId: EncodedData<'ok'>, + oracleId: Encoded.OracleAddress, options: ExtendOracleTtlOptions, ): Promise> & Awaited>> { const oracleExtendTx = await _buildTx(Tag.OracleExtendTx, { @@ -245,8 +247,8 @@ interface ExtendOracleTtlOptions extends ExtendOracleTtlOptionsType {} * @returns Oracle object */ export async function respondToQuery( - oracleId: EncodedData<'ok'>, - queryId: EncodedData<'oq'>, + oracleId: Encoded.OracleAddress, + queryId: Encoded.OracleQueryId, response: string, options: RespondToQueryOptions, ): Promise> & Awaited>> { @@ -279,7 +281,7 @@ interface RespondToQueryOptions extends RespondToQueryOptionsType {} * @returns Oracle object */ export async function getOracleObject( - oracleId: EncodedData<'ok'>, + oracleId: Encoded.OracleAddress, options: { onNode: Node; onAccount: AccountBase }, ): Promise { return { @@ -308,7 +310,7 @@ export async function getOracleObject( } interface GetOracleObjectReturnType extends Awaited> { - id: EncodedData<'ok'>; + id: Encoded.OracleAddress; queries: OracleQueries; // TODO: replace getOracleObject with a class pollQueries: (cb: Parameters[1]) => ReturnType; @@ -348,7 +350,7 @@ export async function registerOracle( }); return { ...await send(oracleRegisterTx, options), - ...await getOracleObject(encode(decode(accountId), 'ok'), options), + ...await getOracleObject(encode(decode(accountId), Encoding.OracleAddress), options), }; } diff --git a/src/spend.ts b/src/spend.ts index 1078eb1ab5..aff6408deb 100644 --- a/src/spend.ts +++ b/src/spend.ts @@ -21,7 +21,7 @@ import { import { _buildTx, BuildTxOptions } from './tx'; import { buildTxHash, unpackTx } from './tx/builder'; import { ArgumentError } from './utils/errors'; -import { EncodedData } from './utils/encoder'; +import { Encoded, Encoding } from './utils/encoder'; import { Tag, AensName } from './tx/builder/constants'; import AccountBase from './account/Base'; @@ -34,7 +34,10 @@ import AccountBase from './account/Base'; * valid * @returns Transaction */ -export async function send(tx: EncodedData<'tx'>, options: SendOptions): Promise { +export async function send( + tx: Encoded.Transaction, + options: SendOptions, +): Promise { // TODO: detect authFun in AccountGa const authFun = options.innerTx === true ? undefined @@ -66,14 +69,18 @@ interface SendReturnType extends Awaited> {} */ export async function spend( amount: number | string, - recipientIdOrName: EncodedData<'ak'> | AensName, + recipientIdOrName: Encoded.AccountAddress | AensName, options: SpendOptions, ): ReturnType { return send( await _buildTx(Tag.SpendTx, { ...options, senderId: await options.onAccount.address(options), - recipientId: await resolveName(recipientIdOrName, 'account_pubkey', options), + recipientId: await resolveName( + recipientIdOrName, + 'account_pubkey', + options, + ), amount, }), options, @@ -95,13 +102,17 @@ interface SpendOptions extends SpendOptionsType {} */ export async function transferFunds( fraction: number | string, - recipientIdOrName: AensName | EncodedData<'ak'>, + recipientIdOrName: AensName | Encoded.AccountAddress, options: TransferFundsOptions, ): ReturnType { if (fraction < 0 || fraction > 1) { throw new ArgumentError('fraction', 'a number between 0 and 1', fraction); } - const recipientId = await resolveName<'ak'>(recipientIdOrName, 'account_pubkey', options); + const recipientId = await resolveName( + recipientIdOrName, + 'account_pubkey', + options, + ); const senderId = await options.onAccount.address(options); const balance = new BigNumber( await getBalance.bind(options.onAccount)(senderId, options), @@ -135,7 +146,7 @@ interface TransferFundsOptions extends TransferFundsOptionsType {} * @returns Object Transaction */ export async function payForTransaction( - transaction: EncodedData<'tx'>, + transaction: Encoded.Transaction, options: PayForTransactionOptions, ): ReturnType { return send( diff --git a/src/tx/builder/address.ts b/src/tx/builder/address.ts index 7bd528b38c..ce18ffe303 100644 --- a/src/tx/builder/address.ts +++ b/src/tx/builder/address.ts @@ -1,7 +1,9 @@ import { ArgumentError, PrefixNotFoundError, TagNotFoundError } from '../../utils/errors'; -import { isKeyOfObject } from '../../utils/other'; import { toBytes } from '../../utils/bytes'; -import { decode, encode, EncodedData } from '../../utils/encoder'; +import { + decode, encode, Encoded, Encoding, +} from '../../utils/encoder'; +import { isItemOfArray } from '../../utils/other'; /** * Map of prefix to ID tag constant @@ -9,16 +11,16 @@ import { decode, encode, EncodedData } from '../../utils/encoder'; * @see {@link https://github.com/aeternity/aeserialization/blob/eb68fe331bd476910394966b7f5ede7a74d37e35/src/aeser_id.erl#L97-L102} * @see {@link https://github.com/aeternity/aeserialization/blob/eb68fe331bd476910394966b7f5ede7a74d37e35/src/aeser_api_encoder.erl#L163-L168} */ -enum PrefixToIdTag { - ak = 1, - nm = 2, - cm = 3, - ok = 4, - ct = 5, - ch = 6, -} +const idTagToEncoding = [ + Encoding.AccountAddress, + Encoding.Name, + Encoding.Commitment, + Encoding.OracleAddress, + Encoding.ContractAddress, + Encoding.Channel, +] as const; -type AddressPrefixes = keyof typeof PrefixToIdTag; +type AddressEncodings = typeof idTagToEncoding[number]; /** * Utility function to create and _id type @@ -26,11 +28,11 @@ type AddressPrefixes = keyof typeof PrefixToIdTag; * @param hashId - Encoded hash * @returns Buffer Buffer with ID tag and decoded HASh */ -export function writeId(hashId: EncodedData): Buffer { +export function writeId(hashId: Encoded.Generic): Buffer { if (typeof hashId !== 'string') throw new ArgumentError('hashId', 'a string', hashId); - const prefix = hashId.slice(0, 2); - if (!isKeyOfObject(prefix, PrefixToIdTag)) throw new TagNotFoundError(prefix); - const idTag = PrefixToIdTag[prefix]; + const encoding = hashId.slice(0, 2); + if (!isItemOfArray(encoding, idTagToEncoding)) throw new TagNotFoundError(encoding); + const idTag = idTagToEncoding.indexOf(encoding) + 1; return Buffer.from([...toBytes(idTag), ...decode(hashId)]); } @@ -40,9 +42,9 @@ export function writeId(hashId: EncodedData): Buffer { * @param buf - Data * @returns Encoided hash string with prefix */ -export function readId(buf: Buffer): EncodedData { +export function readId(buf: Buffer): Encoded.Generic { const idTag = Buffer.from(buf).readUIntBE(0, 1); - const prefix = PrefixToIdTag[idTag] as AddressPrefixes; - if (prefix == null) throw new PrefixNotFoundError(idTag); - return encode(buf.slice(1, buf.length), prefix); + const encoding = idTagToEncoding[idTag - 1]; + if (encoding == null) throw new PrefixNotFoundError(idTag); + return encode(buf.slice(1, buf.length), encoding); } diff --git a/src/tx/builder/field-types/name-id.ts b/src/tx/builder/field-types/name-id.ts index 6d0149562f..388546c4b7 100644 --- a/src/tx/builder/field-types/name-id.ts +++ b/src/tx/builder/field-types/name-id.ts @@ -1,20 +1,20 @@ import { AensName } from '../constants'; import { produceNameId, isNameValid } from '../helpers'; import { writeId, readId } from '../address'; -import { EncodedData } from '../../../utils/encoder'; +import { Encoded } from '../../../utils/encoder'; export default { /** * @param value - AENS name ID */ - serialize(value: AensName | EncodedData<'nm'>): Buffer { + serialize(value: AensName | Encoded.Name): Buffer { return writeId(isNameValid(value) ? produceNameId(value) : value); }, /** * @param value - AENS name ID Buffer */ - deserialize(value: Buffer): EncodedData<'nm'> { - return readId(value) as EncodedData<'nm'>; + deserialize(value: Buffer): Encoded.Name { + return readId(value) as Encoded.Name; }, }; diff --git a/src/tx/builder/helpers.ts b/src/tx/builder/helpers.ts index cdafb3f8f4..88104fb5e6 100644 --- a/src/tx/builder/helpers.ts +++ b/src/tx/builder/helpers.ts @@ -1,14 +1,16 @@ import BigNumber from 'bignumber.js'; -import { hash, genSalt } from '../../utils/crypto'; -import { encode, decode, EncodedData } from '../../utils/encoder'; +import { genSalt, hash } from '../../utils/crypto'; +import { + decode, encode, Encoded, Encoding, +} from '../../utils/encoder'; import { toBytes } from '../../utils/bytes'; import { concatBuffers } from '../../utils/other'; import { + AensName, NAME_BID_RANGES, - NAME_FEE_BID_INCREMENT, NAME_BID_TIMEOUT_BLOCKS, + NAME_FEE_BID_INCREMENT, NAME_MAX_LENGTH_FEE, - AensName, } from './constants'; import { ceil } from '../../utils/bignumber'; import { IllegalBidFeeError } from '../../utils/errors'; @@ -27,12 +29,12 @@ import { readId, writeId } from './address'; * @returns Contract public key */ export function buildContractId( - ownerId: EncodedData<'ak'>, + ownerId: Encoded.AccountAddress, nonce: number | BigNumber, -): EncodedData<'ct'> { +): Encoded.ContractAddress { const ownerIdAndNonce = Buffer.from([...decode(ownerId), ...toBytes(nonce)]); const b2bHash = hash(ownerIdAndNonce); - return encode(b2bHash, 'ct'); + return encode(b2bHash, Encoding.ContractAddress); } /** @@ -44,10 +46,10 @@ export function buildContractId( * @returns Contract public key */ export function oracleQueryId( - senderId: EncodedData<'ak'>, + senderId: Encoded.AccountAddress, nonce: number | BigNumber | string, - oracleId: EncodedData<'ok'>, -): EncodedData<'oq'> { + oracleId: Encoded.OracleAddress, +): Encoded.OracleQueryId { function _int32(val: number | string | BigNumber): Buffer { const nonceBE = toBytes(val, true); return concatBuffers([Buffer.alloc(32 - nonceBE.length), nonceBE]); @@ -56,7 +58,7 @@ export function oracleQueryId( const b2bHash = hash( Buffer.from([...decode(senderId), ..._int32(nonce), ...decode(oracleId)]), ); - return encode(b2bHash, 'oq'); + return encode(b2bHash, Encoding.OracleQueryId); } /** @@ -75,8 +77,8 @@ export function formatSalt(salt: number): Buffer { * @param name - Name to encode * @returns `nm_` prefixed encoded AENS name */ -export function produceNameId(name: AensName): EncodedData<'nm'> { - return encode(hash(name.toLowerCase()), 'nm'); +export function produceNameId(name: AensName): Encoded.Name { + return encode(hash(name.toLowerCase()), Encoding.Name); } /** @@ -87,8 +89,14 @@ export function produceNameId(name: AensName): EncodedData<'nm'> { * @param salt - Random salt * @returns Commitment hash */ -export function commitmentHash(name: AensName, salt: number = genSalt()): EncodedData<'cm'> { - return encode(hash(concatBuffers([Buffer.from(name.toLowerCase()), formatSalt(salt)])), 'cm'); +export function commitmentHash( + name: AensName, + salt: number = genSalt(), +): Encoded.Commitment { + return encode( + hash(concatBuffers([Buffer.from(name.toLowerCase()), formatSalt(salt)])), + Encoding.Commitment, + ); } /** @@ -154,12 +162,12 @@ export function isNameValid(name: string): name is AensName { return name.endsWith(AENS_SUFFIX); } -enum PointerKeyByPrefix { - ak = 'account_pubkey', - ok = 'oracle_pubkey', - ct = 'contract_pubkey', - ch = 'channel', -} +const encodingToPointerKey = { + [Encoding.AccountAddress]: 'account_pubkey', + [Encoding.OracleAddress]: 'oracle_pubkey', + [Encoding.ContractAddress]: 'contract_pubkey', + [Encoding.Channel]: 'channel', +} as const; /** * @category AENS @@ -167,11 +175,11 @@ enum PointerKeyByPrefix { * @returns default AENS pointer key */ export function getDefaultPointerKey( - identifier: EncodedData, -): PointerKeyByPrefix { + identifier: Encoded.Generic, +): typeof encodingToPointerKey[keyof typeof encodingToPointerKey] { decode(identifier); - const prefix = identifier.substring(0, 2) as keyof typeof PointerKeyByPrefix; - return PointerKeyByPrefix[prefix]; + const prefix = identifier.substring(0, 2) as keyof typeof encodingToPointerKey; + return encodingToPointerKey[prefix]; } /** diff --git a/src/tx/builder/index.ts b/src/tx/builder/index.ts index 8c411d8168..5418c0f799 100644 --- a/src/tx/builder/index.ts +++ b/src/tx/builder/index.ts @@ -1,6 +1,6 @@ import { decode as rlpDecode, encode as rlpEncode, NestedUint8Array } from 'rlp'; import { - encode, decode, EncodedData, EncodingType, + decode, encode, Encoded, Encoding, } from '../../utils/encoder'; import { AE_AMOUNT_FORMATS } from '../../utils/amount-formatter'; import { hash } from '../../utils/crypto'; @@ -8,25 +8,24 @@ import { Field } from './field-types'; import { FIELD_TYPES, RawTxObject, + TX_SCHEMA, TxField, - TxTypeSchemas, TxParamsCommon, - TX_SCHEMA, TxSchema, + TxTypeSchemas, } from './schema'; import { Tag } from './constants'; import { - readInt, - readPointers, - writeInt, - buildPointers, - buildContractId, + buildContractId, buildPointers, readInt, readPointers, writeInt, } from './helpers'; import { readId, writeId } from './address'; import { toBytes } from '../../utils/bytes'; import MPTree, { MPTreeBinary } from '../../utils/mptree'; import { - ArgumentError, InvalidTxParamsError, SchemaNotFoundError, DecodeError, + ArgumentError, + DecodeError, + InvalidTxParamsError, + SchemaNotFoundError, } from '../../utils/errors'; import { isKeyOfObject } from '../../utils/other'; import { NamePointer } from '../../apis/node'; @@ -39,7 +38,7 @@ import { NamePointer } from '../../apis/node'; function deserializeField( value: any, type: FIELD_TYPES | Field, - prefix?: EncodingType | EncodingType[], + prefix?: Encoding | Encoding[], ): any { if (value == null) return ''; switch (type) { @@ -60,28 +59,28 @@ function deserializeField( case FIELD_TYPES.bool: return value[0] === 1; case FIELD_TYPES.binary: - return encode(value, prefix as EncodingType); + return encode(value, prefix as Encoding); case FIELD_TYPES.stateTree: - return encode(value, 'ss'); + return encode(value, Encoding.StateTrees); case FIELD_TYPES.string: return value.toString(); case FIELD_TYPES.payload: - return encode(value, 'ba'); + return encode(value, Encoding.Bytearray); case FIELD_TYPES.pointers: return readPointers(value); case FIELD_TYPES.rlpBinary: // eslint-disable-next-line @typescript-eslint/no-use-before-define - return unpackTx(encode(value, 'tx')); + return unpackTx(encode(value, Encoding.Transaction)); case FIELD_TYPES.rlpBinaries: // eslint-disable-next-line @typescript-eslint/no-use-before-define - return value.map((v: Buffer) => unpackTx(encode(v, 'tx'))); + return value.map((v: Buffer) => unpackTx(encode(v, Encoding.Transaction))); case FIELD_TYPES.rawBinary: return value; case FIELD_TYPES.hex: return value.toString('hex'); case FIELD_TYPES.offChainUpdates: // eslint-disable-next-line @typescript-eslint/no-use-before-define - return value.map((v: Buffer) => unpackTx(encode(v, 'tx'))); + return value.map((v: Buffer) => unpackTx(encode(v, Encoding.Transaction))); case FIELD_TYPES.callStack: // TODO: fix this return [readInt(value)]; @@ -138,7 +137,7 @@ function serializeField(value: any, type: FIELD_TYPES | Field, params: any): any return value.map(Buffer.from); case FIELD_TYPES.payload: return typeof value === 'string' && value.split('_')[0] === 'ba' - ? decode(value as EncodedData<'ba'>) + ? decode(value as Encoded.Bytearray) : toBytes(value); case FIELD_TYPES.string: return toBytes(value); @@ -167,7 +166,7 @@ function serializeField(value: any, type: FIELD_TYPES | Field, params: any): any function validateField( value: any, type: FIELD_TYPES | Field, - prefix?: EncodingType | EncodingType[], + prefix?: Encoding | Encoding[], ): string | undefined { // All fields are required if (value == null) return 'Field is required'; @@ -249,8 +248,8 @@ export function unpackRawTx( /** * @category transaction builder */ -export interface BuiltTx { - tx: EncodedData; +export interface BuiltTx { + tx: Encoded.Generic; rlpEncoded: Uint8Array; binary: Uint8Array; txObject: RawTxObject; @@ -275,14 +274,17 @@ export function buildTx( _params: Omit & { VSN?: number }, type: TxType, { - excludeKeys = [], prefix = 'tx', vsn, denomination = AE_AMOUNT_FORMATS.AETTOS, + excludeKeys = [], + prefix = Encoding.Transaction, + vsn, + denomination = AE_AMOUNT_FORMATS.AETTOS, }: { excludeKeys?: string[]; - prefix?: EncodingType; + prefix?: Encoding; vsn?: number; denomination?: AE_AMOUNT_FORMATS; } = {}, -): BuiltTx { +): BuiltTx { const schemas = TX_SCHEMA[type]; vsn ??= Math.max(...Object.keys(schemas).map((a) => +a)); @@ -303,7 +305,7 @@ export function buildTx( } const binary = filteredSchema - .map(([key, fieldType]: [keyof TxSchema, FIELD_TYPES, EncodingType]) => ( + .map(([key, fieldType]: [keyof TxSchema, FIELD_TYPES, Encoding]) => ( serializeField( params[key], fieldType, @@ -314,7 +316,7 @@ export function buildTx( { ...params, ...overrideParams }, type, { - excludeKeys, prefix: 'tx', vsn, denomination, + excludeKeys, prefix: Encoding.Transaction, vsn, denomination, }, ), }, @@ -350,7 +352,7 @@ export interface TxUnpacked { * @returns object.txType Transaction type */ export function unpackTx( - encodedTx: EncodedData<'tx' | 'pi'>, + encodedTx: Encoded.Transaction | Encoded.Poi, txType?: TxType, ): TxUnpacked { const rlpEncoded = decode(encodedTx); @@ -374,11 +376,11 @@ export function unpackTx( * @param rawTx - base64 or rlp encoded transaction * @returns Transaction hash */ -export function buildTxHash(rawTx: EncodedData<'tx'> | Uint8Array): EncodedData<'th'> { +export function buildTxHash(rawTx: Encoded.Transaction | Uint8Array): Encoded.TxHash { const data = typeof rawTx === 'string' && rawTx.startsWith('tx_') ? decode(rawTx) : rawTx; - return encode(hash(data), 'th'); + return encode(hash(data), Encoding.TxHash); } /** @@ -387,7 +389,9 @@ export function buildTxHash(rawTx: EncodedData<'tx'> | Uint8Array): EncodedData< * @param contractTx - Transaction * @returns Contract public key */ -export function buildContractIdByContractTx(contractTx: EncodedData<'tx'>): EncodedData<'ct'> { +export function buildContractIdByContractTx( + contractTx: Encoded.Transaction, +): Encoded.ContractAddress { const { txType, tx } = unpackTx(contractTx); if (![Tag.ContractCreateTx, Tag.GaAttachTx].includes(txType)) { throw new ArgumentError('contractCreateTx', 'a contractCreateTx or gaAttach', txType); diff --git a/src/tx/builder/schema.ts b/src/tx/builder/schema.ts index 9f6493bb49..5aa3ed3c8b 100644 --- a/src/tx/builder/schema.ts +++ b/src/tx/builder/schema.ts @@ -9,7 +9,7 @@ import { Tag } from './constants'; import { Field, uInt, shortUInt, coinAmount, name, nameId, nameFee, deposit, gasLimit, gasPrice, fee, } from './field-types'; -import { EncodedData, EncodingType } from '../../utils/encoder'; +import { Encoded, Encoding } from '../../utils/encoder'; import MPTree from '../../utils/mptree'; import { NamePointer } from '../../apis/node'; @@ -36,7 +36,7 @@ export const DRY_RUN_ACCOUNT = { export type TxField = [ name: string, type: FIELD_TYPES | Field, - prefix?: EncodingType | EncodingType[], + prefix?: Encoding | Encoding[], ]; /** @@ -86,11 +86,11 @@ export const PROTOCOL_VM_ABI = { }, } as const; -type PrefixType = Prefix extends EncodingType - ? EncodedData - : Prefix extends readonly EncodingType[] - ? EncodedData - : EncodedData; +type PrefixType = Prefix extends Encoding + ? Encoded.Generic + : Prefix extends readonly Encoding[] + ? Encoded.Generic + : Encoded.Generic; /** * @category transaction builder @@ -128,9 +128,9 @@ export enum FIELD_TYPES { stateTree, } -interface BuildFieldTypes { +interface BuildFieldTypes { [FIELD_TYPES.id]: PrefixType; - [FIELD_TYPES.ids]: Array>; + [FIELD_TYPES.ids]: Array>; [FIELD_TYPES.string]: string; [FIELD_TYPES.binary]: PrefixType; [FIELD_TYPES.bool]: Boolean; @@ -159,11 +159,11 @@ type UnionToIntersection = ? Intersection : never; type TxElem = readonly [string, FIELD_TYPES | Field] -| readonly [string, FIELD_TYPES, EncodingType | readonly EncodingType[]]; +| readonly [string, FIELD_TYPES, Encoding | readonly Encoding[]]; type BuildTxArgBySchemaType< Type extends FIELD_TYPES | Field, - Prefix extends undefined | EncodingType | readonly EncodingType[], + Prefix extends undefined | Encoding | readonly Encoding[], > = Type extends Field ? Parameters[0] @@ -206,8 +206,8 @@ export const TX_SCHEMA = { ['flags', uInt], ['nonce', shortUInt], ['balance', uInt], - ['gaContract', FIELD_TYPES.id, ['ct', 'nm']], - ['gaAuthFun', FIELD_TYPES.binary, 'cb'], + ['gaContract', FIELD_TYPES.id, [Encoding.ContractAddress, Encoding.Name]], + ['gaAuthFun', FIELD_TYPES.binary, Encoding.ContractBytearray], ], }, [Tag.SignedTx]: { @@ -220,8 +220,8 @@ export const TX_SCHEMA = { [Tag.SpendTx]: { 1: [ ...BASE_TX, - ['senderId', FIELD_TYPES.id, 'ak'], - ['recipientId', FIELD_TYPES.id, ['ak', 'nm']], + ['senderId', FIELD_TYPES.id, Encoding.AccountAddress], + ['recipientId', FIELD_TYPES.id, [Encoding.AccountAddress, Encoding.Name]], ['amount', coinAmount], ['fee', fee], ['ttl', shortUInt], @@ -232,9 +232,9 @@ export const TX_SCHEMA = { [Tag.NamePreclaimTx]: { 1: [ ...BASE_TX, - ['accountId', FIELD_TYPES.id, 'ak'], + ['accountId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], - ['commitmentId', FIELD_TYPES.id, 'cm'], + ['commitmentId', FIELD_TYPES.id, Encoding.Commitment], ['fee', fee], ['ttl', shortUInt], ], @@ -242,7 +242,7 @@ export const TX_SCHEMA = { [Tag.NameClaimTx]: { 2: [ ...BASE_TX, - ['accountId', FIELD_TYPES.id, 'ak'], + ['accountId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], ['name', name], ['nameSalt', uInt], @@ -254,7 +254,7 @@ export const TX_SCHEMA = { [Tag.NameUpdateTx]: { 1: [ ...BASE_TX, - ['accountId', FIELD_TYPES.id, 'ak'], + ['accountId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], ['nameId', nameId], ['nameTtl', uInt], @@ -267,10 +267,10 @@ export const TX_SCHEMA = { [Tag.NameTransferTx]: { 1: [ ...BASE_TX, - ['accountId', FIELD_TYPES.id, 'ak'], + ['accountId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], ['nameId', nameId], - ['recipientId', FIELD_TYPES.id, ['ak', 'nm']], + ['recipientId', FIELD_TYPES.id, [Encoding.AccountAddress, Encoding.Name]], ['fee', fee], ['ttl', shortUInt], ], @@ -278,7 +278,7 @@ export const TX_SCHEMA = { [Tag.NameRevokeTx]: { 1: [ ...BASE_TX, - ['accountId', FIELD_TYPES.id, 'ak'], + ['accountId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], ['nameId', nameId], ['fee', fee], @@ -288,21 +288,21 @@ export const TX_SCHEMA = { [Tag.Contract]: { 1: [ ...BASE_TX, - ['owner', FIELD_TYPES.id, 'ak'], + ['owner', FIELD_TYPES.id, Encoding.AccountAddress], ['ctVersion', FIELD_TYPES.ctVersion], - ['code', FIELD_TYPES.binary, 'cb'], - ['log', FIELD_TYPES.binary, 'cb'], + ['code', FIELD_TYPES.binary, Encoding.ContractBytearray], + ['log', FIELD_TYPES.binary, Encoding.ContractBytearray], ['active', FIELD_TYPES.bool], - ['referers', FIELD_TYPES.ids, 'ak'], + ['referers', FIELD_TYPES.ids, Encoding.AccountAddress], ['deposit', deposit], ], }, [Tag.ContractCreateTx]: { 1: [ ...BASE_TX, - ['ownerId', FIELD_TYPES.id, 'ak'], + ['ownerId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], - ['code', FIELD_TYPES.binary, 'cb'], + ['code', FIELD_TYPES.binary, Encoding.ContractBytearray], ['ctVersion', FIELD_TYPES.ctVersion], ['fee', fee], ['ttl', shortUInt], @@ -310,34 +310,34 @@ export const TX_SCHEMA = { ['amount', coinAmount], ['gasLimit', gasLimit], ['gasPrice', gasPrice], - ['callData', FIELD_TYPES.binary, 'cb'], + ['callData', FIELD_TYPES.binary, Encoding.ContractBytearray], ], }, [Tag.ContractCallTx]: { 1: [ ...BASE_TX, - ['callerId', FIELD_TYPES.id, 'ak'], + ['callerId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], - ['contractId', FIELD_TYPES.id, ['ct', 'nm']], + ['contractId', FIELD_TYPES.id, [Encoding.ContractAddress, Encoding.Name]], ['abiVersion', FIELD_TYPES.abiVersion], ['fee', fee], ['ttl', shortUInt], ['amount', coinAmount], ['gasLimit', gasLimit], ['gasPrice', gasPrice], - ['callData', FIELD_TYPES.binary, 'cb'], + ['callData', FIELD_TYPES.binary, Encoding.ContractBytearray], ], }, [Tag.ContractCall]: { 1: [ ...BASE_TX, - ['callerId', FIELD_TYPES.id, 'ak'], + ['callerId', FIELD_TYPES.id, Encoding.AccountAddress], ['callerNonce', shortUInt], ['height', shortUInt], - ['contractId', FIELD_TYPES.id, 'ct'], + ['contractId', FIELD_TYPES.id, Encoding.ContractAddress], ['gasPrice', gasPrice], ['gasUsed', shortUInt], - ['returnValue', FIELD_TYPES.binary, 'cb'], + ['returnValue', FIELD_TYPES.binary, Encoding.ContractBytearray], ['returnType', FIELD_TYPES.callReturnType], // TODO: add serialization for // :: [ {
:: id, [ :: binary() ], :: binary() } ] @@ -347,7 +347,7 @@ export const TX_SCHEMA = { [Tag.OracleRegisterTx]: { 1: [ ...BASE_TX, - ['accountId', FIELD_TYPES.id, 'ak'], + ['accountId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], ['queryFormat', FIELD_TYPES.string], ['responseFormat', FIELD_TYPES.string], @@ -362,7 +362,7 @@ export const TX_SCHEMA = { [Tag.OracleExtendTx]: { 1: [ ...BASE_TX, - ['oracleId', FIELD_TYPES.id, ['ok', 'nm']], + ['oracleId', FIELD_TYPES.id, [Encoding.OracleAddress, Encoding.Name]], ['nonce', shortUInt], ['oracleTtlType', FIELD_TYPES.ttlType], ['oracleTtlValue', shortUInt], @@ -373,9 +373,9 @@ export const TX_SCHEMA = { [Tag.OracleQueryTx]: { 1: [ ...BASE_TX, - ['senderId', FIELD_TYPES.id, 'ak'], + ['senderId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], - ['oracleId', FIELD_TYPES.id, ['ok', 'nm']], + ['oracleId', FIELD_TYPES.id, [Encoding.OracleAddress, Encoding.Name]], ['query', FIELD_TYPES.string], ['queryFee', coinAmount], ['queryTtlType', FIELD_TYPES.ttlType], @@ -389,9 +389,9 @@ export const TX_SCHEMA = { [Tag.OracleResponseTx]: { 1: [ ...BASE_TX, - ['oracleId', FIELD_TYPES.id, 'ok'], + ['oracleId', FIELD_TYPES.id, Encoding.OracleAddress], ['nonce', shortUInt], - ['queryId', FIELD_TYPES.binary, 'oq'], + ['queryId', FIELD_TYPES.binary, Encoding.OracleQueryId], ['response', FIELD_TYPES.string], ['responseTtlType', FIELD_TYPES.ttlType], ['responseTtlValue', shortUInt], @@ -402,9 +402,9 @@ export const TX_SCHEMA = { [Tag.ChannelCreateTx]: { 2: [ ...BASE_TX, - ['initiator', FIELD_TYPES.id, 'ak'], + ['initiator', FIELD_TYPES.id, Encoding.AccountAddress], ['initiatorAmount', uInt], - ['responder', FIELD_TYPES.id, 'ak'], + ['responder', FIELD_TYPES.id, Encoding.AccountAddress], ['responderAmount', uInt], ['channelReserve', uInt], ['lockPeriod', uInt], @@ -419,8 +419,8 @@ export const TX_SCHEMA = { [Tag.ChannelCloseMutualTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['initiatorAmountFinal', uInt], ['responderAmountFinal', uInt], ['ttl', shortUInt], @@ -431,8 +431,8 @@ export const TX_SCHEMA = { [Tag.ChannelCloseSoloTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['payload', FIELD_TYPES.binary, 'tx'], ['poi', FIELD_TYPES.binary, 'pi'], ['ttl', shortUInt], @@ -443,8 +443,8 @@ export const TX_SCHEMA = { [Tag.ChannelSlashTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['payload', FIELD_TYPES.binary, 'tx'], ['poi', FIELD_TYPES.binary, 'pi'], ['ttl', shortUInt], @@ -455,8 +455,8 @@ export const TX_SCHEMA = { [Tag.ChannelDepositTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['amount', uInt], ['ttl', shortUInt], ['fee', fee], @@ -468,8 +468,8 @@ export const TX_SCHEMA = { [Tag.ChannelWithdrawTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['toId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['toId', FIELD_TYPES.id, Encoding.AccountAddress], ['amount', uInt], ['ttl', shortUInt], ['fee', fee], @@ -481,8 +481,8 @@ export const TX_SCHEMA = { [Tag.ChannelSettleTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['initiatorAmountFinal', uInt], ['responderAmountFinal', uInt], ['ttl', shortUInt], @@ -493,11 +493,11 @@ export const TX_SCHEMA = { [Tag.ChannelForceProgressTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['payload', FIELD_TYPES.binary, 'tx'], ['round', shortUInt], - ['update', FIELD_TYPES.binary, 'cb'], + ['update', FIELD_TYPES.binary, Encoding.ContractBytearray], ['stateHash', FIELD_TYPES.binary, 'st'], ['offChainTrees', FIELD_TYPES.stateTree], ['ttl', shortUInt], @@ -508,7 +508,7 @@ export const TX_SCHEMA = { [Tag.ChannelOffChainTx]: { 2: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], ['round', shortUInt], ['stateHash', FIELD_TYPES.binary, 'st'], ], @@ -516,8 +516,8 @@ export const TX_SCHEMA = { [Tag.Channel]: { 3: [ ...BASE_TX, - ['initiator', FIELD_TYPES.id, 'ak'], - ['responder', FIELD_TYPES.id, 'ak'], + ['initiator', FIELD_TYPES.id, Encoding.AccountAddress], + ['responder', FIELD_TYPES.id, Encoding.AccountAddress], ['channelAmount', uInt], ['initiatorAmount', uInt], ['responderAmount', uInt], @@ -529,15 +529,15 @@ export const TX_SCHEMA = { ['soloRound', uInt], ['lockPeriod', uInt], ['lockedUntil', uInt], - ['initiatorAuth', FIELD_TYPES.binary, 'cb'], - ['responderAuth', FIELD_TYPES.binary, 'cb'], + ['initiatorAuth', FIELD_TYPES.binary, Encoding.ContractBytearray], + ['responderAuth', FIELD_TYPES.binary, Encoding.ContractBytearray], ], }, [Tag.ChannelSnapshotSoloTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], - ['fromId', FIELD_TYPES.id, 'ak'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], + ['fromId', FIELD_TYPES.id, Encoding.AccountAddress], ['payload', FIELD_TYPES.binary, 'tx'], ['ttl', shortUInt], ['fee', fee], @@ -547,43 +547,43 @@ export const TX_SCHEMA = { [Tag.ChannelOffChainUpdateTransfer]: { 1: [ ...BASE_TX, - ['from', FIELD_TYPES.id, 'ak'], - ['to', FIELD_TYPES.id, 'ak'], + ['from', FIELD_TYPES.id, Encoding.AccountAddress], + ['to', FIELD_TYPES.id, Encoding.AccountAddress], ['amount', uInt], ], }, [Tag.ChannelOffChainUpdateDeposit]: { 1: [ ...BASE_TX, - ['from', FIELD_TYPES.id, 'ak'], + ['from', FIELD_TYPES.id, Encoding.AccountAddress], ['amount', uInt], ], }, [Tag.ChannelOffChainUpdateWithdraw]: { 1: [ ...BASE_TX, - ['from', FIELD_TYPES.id, 'ak'], + ['from', FIELD_TYPES.id, Encoding.AccountAddress], ['amount', uInt], ], }, [Tag.ChannelOffChainUpdateCreateContract]: { 1: [ ...BASE_TX, - ['owner', FIELD_TYPES.id, 'ak'], + ['owner', FIELD_TYPES.id, Encoding.AccountAddress], ['ctVersion', FIELD_TYPES.ctVersion], - ['code', FIELD_TYPES.binary, 'cb'], + ['code', FIELD_TYPES.binary, Encoding.ContractBytearray], ['deposit', uInt], - ['callData', FIELD_TYPES.binary, 'cb'], + ['callData', FIELD_TYPES.binary, Encoding.ContractBytearray], ], }, [Tag.ChannelOffChainUpdateCallContract]: { 1: [ ...BASE_TX, - ['caller', FIELD_TYPES.id, 'ak'], - ['contract', FIELD_TYPES.id, 'ct'], + ['caller', FIELD_TYPES.id, Encoding.AccountAddress], + ['contract', FIELD_TYPES.id, Encoding.ContractAddress], ['abiVersion', FIELD_TYPES.abiVersion], ['amount', uInt], - ['callData', FIELD_TYPES.binary, 'cb'], + ['callData', FIELD_TYPES.binary, Encoding.ContractBytearray], ['callStack', FIELD_TYPES.callStack], ['gasPrice', gasPrice], ['gasLimit', gasLimit], @@ -592,10 +592,10 @@ export const TX_SCHEMA = { [Tag.ChannelClientReconnectTx]: { 1: [ ...BASE_TX, - ['channelId', FIELD_TYPES.id, 'ch'], + ['channelId', FIELD_TYPES.id, Encoding.Channel], ['round', shortUInt], ['role', FIELD_TYPES.string], - ['pubkey', FIELD_TYPES.id, 'ak'], + ['pubkey', FIELD_TYPES.id, Encoding.AccountAddress], ], }, [Tag.TreesPoi]: { @@ -672,23 +672,23 @@ export const TX_SCHEMA = { [Tag.GaAttachTx]: { 1: [ ...BASE_TX, - ['ownerId', FIELD_TYPES.id, 'ak'], + ['ownerId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], - ['code', FIELD_TYPES.binary, 'cb'], + ['code', FIELD_TYPES.binary, Encoding.ContractBytearray], ['authFun', FIELD_TYPES.rawBinary], ['ctVersion', FIELD_TYPES.ctVersion], ['fee', fee], ['ttl', shortUInt], ['gasLimit', gasLimit], ['gasPrice', gasPrice], - ['callData', FIELD_TYPES.binary, 'cb'], + ['callData', FIELD_TYPES.binary, Encoding.ContractBytearray], ], }, [Tag.GaMetaTx]: { 2: [ ...BASE_TX, - ['gaId', FIELD_TYPES.id, 'ak'], - ['authData', FIELD_TYPES.binary, 'cb'], + ['gaId', FIELD_TYPES.id, Encoding.AccountAddress], + ['authData', FIELD_TYPES.binary, Encoding.ContractBytearray], ['abiVersion', FIELD_TYPES.abiVersion], ['fee', fee], ['gasLimit', gasLimit], @@ -699,7 +699,7 @@ export const TX_SCHEMA = { [Tag.PayingForTx]: { 1: [ ...BASE_TX, - ['payerId', FIELD_TYPES.id, 'ak'], + ['payerId', FIELD_TYPES.id, Encoding.AccountAddress], ['nonce', shortUInt], ['fee', fee], ['tx', FIELD_TYPES.rlpBinary], diff --git a/src/tx/index.ts b/src/tx/index.ts index ede99a75e8..bf5221720a 100644 --- a/src/tx/index.ts +++ b/src/tx/index.ts @@ -31,7 +31,7 @@ import { ArgumentError, UnsupportedProtocolError, UnknownTxError, InvalidTxParamsError, } from '../utils/errors'; import Node from '../Node'; -import { EncodedData } from '../utils/encoder'; +import { Encoded } from '../utils/encoder'; import { buildTx as syncBuildTx, unpackTx } from './builder/index'; import { isKeyOfObject } from '../utils/other'; import { AE_AMOUNT_FORMATS } from '../utils/amount-formatter'; @@ -103,7 +103,7 @@ export async function prepareTxParams( } interface PrepareTxParamsOptions extends Pick { - senderId: EncodedData<'ak'>; + senderId: Encoded.AccountAddress; absoluteTtl?: boolean; strategy?: 'continuity' | 'max'; onNode: Node; @@ -125,11 +125,12 @@ export async function _buildTx( denomination?: AE_AMOUNT_FORMATS; absoluteTtl?: boolean; } - & (TxType extends Tag.OracleExtendTx | Tag.OracleResponseTx ? { callerId: EncodedData<'ak'> } : {}) + & (TxType extends Tag.OracleExtendTx | Tag.OracleResponseTx + ? { callerId: Encoded.AccountAddress } : {}) & (TxType extends Tag.ContractCreateTx | Tag.GaAttachTx ? { ctVersion?: CtVersion } : {}) & (TxType extends Tag.ContractCallTx | Tag.OracleRegisterTx ? { abiVersion?: ABI_VERSIONS } : {}), -): Promise> { +): Promise { // TODO: avoid this assertion const params = _params as unknown as TxParamsCommon & { onNode: Node }; let senderKey: keyof TxParamsCommon | ''; diff --git a/src/tx/validator.ts b/src/tx/validator.ts index 9ef0fca8fd..db08521cdd 100644 --- a/src/tx/validator.ts +++ b/src/tx/validator.ts @@ -1,18 +1,25 @@ import BigNumber from 'bignumber.js'; -import { verify, hash } from '../utils/crypto'; +import { hash, verify } from '../utils/crypto'; import { - PROTOCOL_VM_ABI, RawTxObject, TxSchema, TxParamsCommon, TxTypeSchemas, CtVersion, + CtVersion, + PROTOCOL_VM_ABI, + RawTxObject, + TxParamsCommon, + TxSchema, + TxTypeSchemas, } from './builder/schema'; import { Tag } from './builder/constants'; import { TxUnpacked, unpackTx } from './builder'; import { UnsupportedProtocolError } from '../utils/errors'; import { concatBuffers, isKeyOfObject } from '../utils/other'; -import { encode, decode, EncodedData } from '../utils/encoder'; +import { + decode, encode, Encoded, Encoding, +} from '../utils/encoder'; import Node from '../Node'; interface Account { balance: bigint; - id: EncodedData<'ak'>; + id: Encoded.AccountAddress; nonce: number; } @@ -36,7 +43,7 @@ type Validator = ( nameFee?: number; ctVersion?: Partial; abiVersion?: number; - contractId?: EncodedData<'ct'>; + contractId?: Encoded.ContractAddress; }, options: { account?: Account; @@ -53,13 +60,13 @@ const validators: Validator[] = []; const getSenderAddress = ( tx: TxParamsCommon | RawTxObject, -): EncodedData<'ak'> | undefined => [ +): Encoded.AccountAddress | undefined => [ 'senderId', 'accountId', 'ownerId', 'callerId', 'oracleId', 'fromId', 'initiator', 'gaId', 'payerId', ] .map((key: keyof TxSchema) => tx[key]) .filter((a) => a) - .map((a) => a?.toString().replace(/^ok_/, 'ak_'))[0] as EncodedData<'ak'> | undefined; + .map((a) => a?.toString().replace(/^ok_/, 'ak_'))[0] as Encoded.AccountAddress | undefined; /** * Transaction Validator @@ -73,7 +80,7 @@ const getSenderAddress = ( * @example const errors = await verifyTransaction(transaction, node) */ export default async function verifyTransaction( - transaction: EncodedData<'tx' | 'pi'>, + transaction: Encoded.Transaction | Encoded.Poi, node: Node, parentTxTypes: Tag[] = [], ): Promise { @@ -86,7 +93,7 @@ export default async function verifyTransaction( : node.getAccountByPubkey(address) .catch(() => ({ id: address, balance: 0n, nonce: 0 })) // TODO: remove after fixing https://github.com/aeternity/aepp-sdk-js/issues/1537 - .then((acc) => ({ ...acc, id: acc.id as EncodedData<'ak'> })), + .then((acc) => ({ ...acc, id: acc.id as Encoded.AccountAddress })), node.getCurrentKeyBlockHeight(), node.getNodeInfo(), ]); @@ -125,7 +132,7 @@ validators.push( async ({ encodedTx, tx }, { node, parentTxTypes, txType }) => { if ((encodedTx ?? tx) === undefined) return []; return verifyTransaction( - encode((encodedTx ?? tx).rlpEncoded, 'tx'), + encode((encodedTx ?? tx).rlpEncoded, Encoding.Transaction), node, [...parentTxTypes, txType], ); @@ -202,7 +209,7 @@ validators.push( }, async ({ contractId }, { txType, node }) => { if (Tag.ContractCallTx !== txType) return []; - contractId = contractId as EncodedData<'ct'>; + contractId = contractId as Encoded.ContractAddress; try { const { active } = await node.getContract(contractId); if (active) return []; diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts index f4b5cbe0d1..5a34d713aa 100644 --- a/src/utils/crypto.ts +++ b/src/utils/crypto.ts @@ -22,7 +22,7 @@ import { encode as varuintEncode } from 'varuint-bitcoin'; import { str2buf } from './bytes'; import { concatBuffers } from './other'; import { - encode, decode, sha256hash, EncodedData, EncodingType, + decode, encode, Encoded, Encoding, sha256hash, } from './encoder'; const Ecb = aesjs.ModeOfOperation.ecb; @@ -32,10 +32,10 @@ const Ecb = aesjs.ModeOfOperation.ecb; * @param secret - Private key * @returns Public key encoded as address */ -export function getAddressFromPriv(secret: string | Uint8Array): EncodedData<'ak'> { +export function getAddressFromPriv(secret: string | Uint8Array): Encoded.AccountAddress { const secretBuffer = typeof secret === 'string' ? str2buf(secret) : secret; const keys = nacl.sign.keyPair.fromSecretKey(secretBuffer); - return encode(keys.publicKey, 'ak'); + return encode(keys.publicKey, Encoding.AccountAddress); } /** @@ -44,9 +44,12 @@ export function getAddressFromPriv(secret: string | Uint8Array): EncodedData<'ak * @param prefix - Transaction prefix. Default: 'ak' * @returns is valid */ -export function isAddressValid(address: string, prefix: EncodingType = 'ak'): boolean { +export function isAddressValid( + address: string, + prefix: Encoding = Encoding.AccountAddress, +): boolean { try { - decode(address as EncodedData); + decode(address as Encoded.Generic); return true; } catch (e) { return false; @@ -90,10 +93,13 @@ export function hash(input: Data): Buffer { * @param nonce - Round when contract was created * @returns Contract address */ -export function encodeContractAddress(owner: EncodedData<'ak'>, nonce: number): EncodedData<'ct'> { +export function encodeContractAddress( + owner: Encoded.AccountAddress, + nonce: number, +): Encoded.ContractAddress { const publicKey = decode(owner); const binary = concatBuffers([publicKey, encodeUnsigned(nonce)]); - return encode(hash(binary), 'ct'); + return encode(hash(binary), Encoding.ContractAddress); } // KEY-PAIR HELPERS @@ -113,9 +119,11 @@ export function generateKeyPairFromSecret(secret: Uint8Array): SignKeyPair { * @returns Key pair */ export function generateKeyPair(raw: true): { publicKey: Buffer; secretKey: Buffer }; -export function generateKeyPair(raw?: false): { publicKey: EncodedData<'ak'>; secretKey: string }; +export function generateKeyPair(raw?: false): { + publicKey: Encoded.AccountAddress; secretKey: string; +}; export function generateKeyPair(raw = false): { - publicKey: EncodedData<'ak'> | Buffer; + publicKey: Encoded.AccountAddress | Buffer; secretKey: string | Buffer; } { const keyPair = nacl.sign.keyPair(); @@ -129,7 +137,7 @@ export function generateKeyPair(raw = false): { }; } return { - publicKey: encode(publicBuffer, 'ak'), + publicKey: encode(publicBuffer, Encoding.AccountAddress), secretKey: secretBuffer.toString('hex'), }; } diff --git a/src/utils/encoder-types.ts b/src/utils/encoder-types.ts new file mode 100644 index 0000000000..be4c4d99e0 --- /dev/null +++ b/src/utils/encoder-types.ts @@ -0,0 +1,63 @@ +/** + * @category transaction builder + * @see {@link https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md} + * @see {@link https://github.com/aeternity/aeserialization/blob/eb68fe331bd476910394966b7f5ede7a74d37e35/src/aeser_api_encoder.erl#L205-L230} + */ +export enum Encoding { + KeyBlockHash = 'kh', + MicroBlockHash = 'mh', + BlockPofHash = 'bf', + BlockTxHash = 'bx', + BlockStateHash = 'bs', + Channel = 'ch', + ContractAddress = 'ct', + ContractBytearray = 'cb', + ContractStoreKey = 'ck', + ContractStoreValue = 'cv', + Transaction = 'tx', + TxHash = 'th', + OracleAddress = 'ok', + OracleQuery = 'ov', + OracleQueryId = 'oq', + OracleResponse = 'or', + AccountAddress = 'ak', + Signature = 'sg', + Commitment = 'cm', + PeerPubkey = 'pp', + Name = 'nm', + State = 'st', + Poi = 'pi', + StateTrees = 'ss', + CallStateTree = 'cs', + Bytearray = 'ba', +} + +export type KeyBlockHash = `${Encoding.KeyBlockHash}_${string}`; +export type MicroBlockHash = `${Encoding.MicroBlockHash}_${string}`; +export type BlockPofHash = `${Encoding.BlockPofHash}_${string}`; +export type BlockTxHash = `${Encoding.BlockTxHash}_${string}`; +export type BlockStateHash = `${Encoding.BlockStateHash}_${string}`; +export type Channel = `${Encoding.Channel}_${string}`; +export type ContractAddress = `${Encoding.ContractAddress}_${string}`; +export type ContractBytearray = `${Encoding.ContractBytearray}_${string}`; +export type ContractStoreKey = `${Encoding.ContractStoreKey}_${string}`; +export type ContractStoreValue = `${Encoding.ContractStoreValue}_${string}`; +export type Transaction = `${Encoding.Transaction}_${string}`; +export type TxHash = `${Encoding.TxHash}_${string}`; +export type OracleAddress = `${Encoding.OracleAddress}_${string}`; +export type OracleQuery = `${Encoding.OracleQuery}_${string}`; +export type OracleQueryId = `${Encoding.OracleQueryId}_${string}`; +export type OracleResponse = `${Encoding.OracleResponse}_${string}`; +export type AccountAddress = `${Encoding.AccountAddress}_${string}`; +export type Signature = `${Encoding.Signature}_${string}`; +export type Commitment = `${Encoding.Commitment}_${string}`; +export type PeerPubkey = `${Encoding.PeerPubkey}_${string}`; +export type Name = `${Encoding.Name}_${string}`; +export type State = `${Encoding.State}_${string}`; +export type Poi = `${Encoding.Poi}_${string}`; +export type StateTrees = `${Encoding.StateTrees}_${string}`; +export type CallStateTree = `${Encoding.CallStateTree}_${string}`; +export type Bytearray = `${Encoding.Bytearray}_${string}`; + +export type Generic = `${Type}_${string}`; +export type Any = `${Encoding}_${string}`; diff --git a/src/utils/encoder.ts b/src/utils/encoder.ts index 2a0eca5d10..d94fd117f3 100644 --- a/src/utils/encoder.ts +++ b/src/utils/encoder.ts @@ -6,7 +6,11 @@ import { InvalidChecksumError, PayloadLengthError, } from './errors'; -import { concatBuffers } from './other'; +import { concatBuffers, isKeyOfObject } from './other'; +import * as Encoded from './encoder-types'; +import { Encoding } from './encoder-types'; + +export { Encoded, Encoding }; /** * Calculate SHA256 hash of `input` @@ -17,35 +21,63 @@ export function sha256hash(input: Uint8Array | string): Buffer { return new Sha256().update(input).digest(); } -// based on https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md -const base64Types = ['ba', 'cb', 'or', 'ov', 'pi', 'ss', 'cs', 'ck', 'cv', 'st', 'tx'] as const; -const base58Types = ['ak', 'bf', 'bs', 'bx', 'ch', 'cm', 'ct', 'kh', 'mh', 'nm', 'ok', 'oq', 'pp', 'sg', 'th'] as const; - -export type EncodingType = typeof base64Types[number] | typeof base58Types[number]; -export type EncodedData = `${Type}_${string}`; +/** + * @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, +] as const; +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.Signature, + Encoding.Commitment, + Encoding.PeerPubkey, + Encoding.Name, +] as const; /** * @see {@link https://github.com/aeternity/aeserialization/blob/eb68fe331bd476910394966b7f5ede7a74d37e35/src/aeser_api_encoder.erl#L261-L286} */ -const byteSizeForType: { [name in EncodingType]?: number } = { - kh: 32, - mh: 32, - bf: 32, - bx: 32, - bs: 32, - ch: 32, - ct: 32, - th: 32, - ok: 32, - oq: 32, - ak: 32, - sg: 64, - cm: 32, - pp: 32, - st: 32, +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.Signature]: 64, + [Encoding.Commitment]: 32, + [Encoding.PeerPubkey]: 32, + [Encoding.State]: 32, } as const; -function ensureValidLength(data: Uint8Array, type: EncodingType): void { +function ensureValidLength(data: Uint8Array, type: Encoding): void { + 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`); @@ -71,7 +103,7 @@ const base58 = { decode: (string: string) => getPayload(Buffer.from(bs58Decode(string))), }; -const parseType = (maybeType: unknown): [EncodingType, typeof base64] => { +const parseType = (maybeType: unknown): [Encoding, typeof base64] => { const base64Type = base64Types.find((t) => t === maybeType); if (base64Type != null) return [base64Type, base64]; const base58Type = base58Types.find((t) => t === maybeType); @@ -85,7 +117,7 @@ const parseType = (maybeType: unknown): [EncodingType, typeof base64] => { * (ex tx_..., sg_..., ak_....) * @returns Decoded data */ -export function decode(data: EncodedData): Buffer { +export function decode(data: Encoded.Any): Buffer { 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}`); @@ -101,7 +133,10 @@ export function decode(data: EncodedData): Buffer { * @param type - Prefix of Transaction * @returns Encoded string Base58check or Base64check data */ -export function encode(data: Uint8Array, type: Type): EncodedData { +export function encode( + data: Uint8Array, + type: Type, +): Encoded.Generic { const [, encoder] = parseType(type); ensureValidLength(data, type); return `${type}_${encoder.encode(data)}`; diff --git a/src/utils/hd-wallet.ts b/src/utils/hd-wallet.ts index a36a14cb55..4e43f93c8b 100644 --- a/src/utils/hd-wallet.ts +++ b/src/utils/hd-wallet.ts @@ -2,7 +2,7 @@ import nacl from 'tweetnacl'; import { full as hmac } from 'tweetnacl-auth'; import { fromString } from 'bip32-path'; import { decryptKey, encryptKey } from './crypto'; -import { encode } from './encoder'; +import { encode, Encoding } from './encoder'; import { CryptographyError } from './errors'; import { bytesToHex } from './bytes'; import { concatBuffers } from './other'; @@ -93,7 +93,7 @@ function formatAccount(keys: nacl.SignKeyPair): Account { const { secretKey, publicKey } = keys; return { secretKey: bytesToHex(secretKey), - publicKey: encode(publicKey, 'ak'), + publicKey: encode(publicKey, Encoding.AccountAddress), }; } diff --git a/src/utils/other.ts b/src/utils/other.ts index 5995346e25..02980eaecc 100644 --- a/src/utils/other.ts +++ b/src/utils/other.ts @@ -27,12 +27,18 @@ export const concatBuffers = isWebpack4Buffer /** * Object key type guard - * @param key - Object key - * @param object - object + * @param key - Maybe object key + * @param object - Object */ -export function isKeyOfObject( - key: string | number | symbol, - object: T, -): key is keyof T { +export function isKeyOfObject(key: string | number | symbol, object: T): key is keyof T { return key in object; } + +/** + * Array item type guard + * @param item - Maybe array item + * @param array - Array + */ +export function isItemOfArray(item: any, array: readonly T[]): item is T { + return array.includes(item); +} diff --git a/test/integration/accounts.ts b/test/integration/accounts.ts index 89b3545f84..ead759afa3 100644 --- a/test/integration/accounts.ts +++ b/test/integration/accounts.ts @@ -24,7 +24,7 @@ import { generateKeyPair, AE_AMOUNT_FORMATS, UnavailableAccountError, TypeError, ArgumentError, InvalidKeypairError, UnexpectedTsError, } from '../../src'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; describe('Accounts', () => { let aeSdk: AeSdk; @@ -152,7 +152,7 @@ describe('Accounts', () => { }); describe('Make operation on specific account without changing of current account', () => { - let address: EncodedData<'ak'>; + let address: Encoded.AccountAddress; before(async () => { address = await aeSdk.address(); diff --git a/test/integration/chain.ts b/test/integration/chain.ts index 20c24e5c76..c28739f085 100644 --- a/test/integration/chain.ts +++ b/test/integration/chain.ts @@ -22,7 +22,7 @@ import { getSdk } from '.'; import { generateKeyPair, AeSdk, Tag, UnexpectedTsError, } from '../../src'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; describe('Node Chain', () => { let aeSdk: AeSdk; @@ -68,7 +68,9 @@ describe('Node Chain', () => { it('Get key block', async () => { const { keyBlock } = await aeSdkWithoutAccount.getCurrentGeneration(); - const keyBlockByHash = await aeSdkWithoutAccount.getKeyBlock(keyBlock.hash as EncodedData<'kh'>); + // TODO type should be corrected in node api + const keyBlockByHash = await aeSdkWithoutAccount + .getKeyBlock(keyBlock.hash as Encoded.KeyBlockHash); const keyBlockByHeight = await aeSdkWithoutAccount.getKeyBlock(keyBlock.height); keyBlockByHash.should.be.an('object'); keyBlockByHeight.should.be.an('object'); @@ -76,7 +78,9 @@ describe('Node Chain', () => { it('Get generation', async () => { const { keyBlock } = await aeSdkWithoutAccount.getCurrentGeneration(); - const genByHash = await aeSdkWithoutAccount.getGeneration(keyBlock.hash as EncodedData<'kh'>); + // TODO type should be corrected in node api + const genByHash = await aeSdkWithoutAccount + .getGeneration(keyBlock.hash as Encoded.KeyBlockHash); const genByHeight = await aeSdkWithoutAccount.getGeneration(keyBlock.height); genByHash.should.be.an('object'); genByHeight.should.be.an('object'); @@ -112,7 +116,7 @@ describe('Node Chain', () => { }); const accounts = new Array(10).fill(undefined).map(() => generateKeyPair()); - const transactions: Array> = []; + const transactions: Encoded.TxHash[] = []; it('multiple spends from one account', async () => { const { nextNonce } = await aeSdk.api.getAccountNextNonce(await aeSdk.address()); diff --git a/test/integration/channel.ts b/test/integration/channel.ts index 900261294b..9a1a37855a 100644 --- a/test/integration/channel.ts +++ b/test/integration/channel.ts @@ -29,7 +29,7 @@ import { pause } from '../../src/utils/other'; import Channel from '../../src/channel'; import { ChannelOptions, send } from '../../src/channel/internal'; import MemoryAccount from '../../src/account/Memory'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded, Encoding } from '../../src/utils/encoder'; import { appendSignature } from '../../src/channel/handlers'; const wsUrl = process.env.TEST_WS_URL ?? 'ws://localhost:3014/channel'; @@ -61,7 +61,7 @@ describe('Channel', () => { let responderShouldRejectUpdate: number | boolean; let existingChannelId: string; let offchainTx: string; - let contractAddress: EncodedData<'ct'>; + let contractAddress: Encoded.ContractAddress; let callerNonce: number; let contract: any; const initiatorSign: sinon.SinonSpy = sinon @@ -215,7 +215,7 @@ describe('Channel', () => { }]), }), ); - const { txType } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelOffChainTx); expect(sign.firstCall.args[1]).to.eql({ @@ -271,7 +271,7 @@ describe('Channel', () => { }]), }), ); - const { txType } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelOffChainTx); expect(sign.firstCall.args[1]).to.eql({ updates: [ @@ -333,28 +333,32 @@ describe('Channel', () => { }); it('can get proof of inclusion', async () => { - const initiatorAddr: EncodedData<'ak'> = await aeSdkInitiatior.address(); - const responderAddr: EncodedData<'ak'> = await aeSdkResponder.address(); + const initiatorAddr: Encoded.AccountAddress = await aeSdkInitiatior.address(); + const responderAddr: Encoded.AccountAddress = await aeSdkResponder.address(); const params = { accounts: [initiatorAddr, responderAddr] }; - const initiatorPoi: EncodedData<'pi'> = await initiatorCh.poi(params); + const initiatorPoi: Encoded.Poi = await initiatorCh.poi(params); expect(initiatorPoi).to.be.equal(await responderCh.poi(params)); initiatorPoi.should.be.a('string'); const unpackedInitiatorPoi = unpackTx(initiatorPoi, Tag.TreesPoi); // TODO: move to `unpackTx`/`MPTree` - function getAccountBalance(address: EncodedData<'ak'>): string { + function getAccountBalance(address: Encoded.AccountAddress): string { const addressHex = decode(address).toString('hex'); const treeNode = unpackedInitiatorPoi.tx.accounts[0].get(addressHex); assertNotNull(treeNode); - const { balance, ...account } = unpackTx(encode(treeNode, 'tx'), Tag.Account).tx; + const { balance, ...account } = unpackTx( + encode(treeNode, Encoding.Transaction), + Tag.Account, + ).tx; expect(account).to.eql({ tag: 10, VSN: 1, nonce: 0 }); return balance.toString(); } expect(getAccountBalance(initiatorAddr)).to.eql('89999999999999999997'); expect(getAccountBalance(responderAddr)).to.eql('110000000000000000003'); - expect(buildTx(unpackedInitiatorPoi.tx, unpackedInitiatorPoi.txType, { prefix: 'pi' }).tx) - .to.equal(initiatorPoi); + expect( + buildTx(unpackedInitiatorPoi.tx, unpackedInitiatorPoi.txType, { prefix: Encoding.Poi }).tx, + ).to.equal(initiatorPoi); }); it('can send a message', async () => { @@ -419,7 +423,7 @@ describe('Channel', () => { }], }), ); - const { txType, tx } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType, tx } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelWithdrawTx); tx.should.eql({ ...tx, @@ -472,7 +476,7 @@ describe('Channel', () => { }], }), ); - const { txType, tx } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType, tx } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelWithdrawTx); tx.should.eql({ ...tx, @@ -549,7 +553,7 @@ describe('Channel', () => { }]), }), ); - const { txType, tx } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType, tx } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelDepositTx); tx.should.eql({ ...tx, @@ -590,7 +594,7 @@ describe('Channel', () => { }], }), ); - const { txType, tx } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType, tx } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelDepositTx); tx.should.eql({ ...tx, @@ -635,7 +639,7 @@ describe('Channel', () => { ); sinon.assert.calledOnce(sign); sinon.assert.calledWithExactly(sign, sinon.match.string); - const { txType, tx } = unpackTx(sign.firstCall.args[0] as EncodedData<'tx'>); + const { txType, tx } = unpackTx(sign.firstCall.args[0] as Encoded.Transaction); txType.should.equal(Tag.ChannelCloseMutualTx); tx.should.eql({ ...tx, @@ -919,7 +923,7 @@ describe('Channel', () => { it('can get balances', async () => { const initiatorAddr = await aeSdkInitiatior.address(); const responderAddr = await aeSdkResponder.address(); - const contractAddr = encode(decode(contractAddress), 'ak'); + const contractAddr = encode(decode(contractAddress), Encoding.AccountAddress); const addresses = [initiatorAddr, responderAddr, contractAddr]; const balances = await initiatorCh.balances(addresses); balances.should.be.an('object'); @@ -1160,7 +1164,7 @@ describe('Channel', () => { 100, async (transaction) => appendSignature( await aeSdkResponder.signTransaction(transaction), - async (tx) => (aeSdkInitiatior.signTransaction(tx) as Promise>), + async (tx) => (aeSdkInitiatior.signTransaction(tx) as Promise), ), ); result.accepted.should.equal(true); diff --git a/test/integration/contract-aci.ts b/test/integration/contract-aci.ts index f58b7819b9..ed7c4a35cb 100644 --- a/test/integration/contract-aci.ts +++ b/test/integration/contract-aci.ts @@ -32,7 +32,7 @@ import { IllegalArgumentError, } from '../../src'; import { getSdk } from '.'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; import { ContractInstance } from '../../src/contract/aci'; import { Aci } from '../../src/apis/compiler'; @@ -145,9 +145,9 @@ const notExistingContractAddress = 'ct_ptREMvyDbSh1d38t4WgYgac5oLsa2v9xwYFnG7eUW describe('Contract instance', () => { let aeSdk: AeSdk; let testContract: ContractInstance; - let testContractAddress: EncodedData<'ct'>; + let testContractAddress: Encoded.ContractAddress; let testContractAci: Aci; - let testContractBytecode: EncodedData<'cb'>; + let testContractBytecode: Encoded.ContractBytearray; before(async () => { aeSdk = await getSdk(2); @@ -436,11 +436,11 @@ describe('Contract instance', () => { }); const getDuplicateLog = (): Array<{ - address: EncodedData<'ct'>; - data: EncodedData<'cb'>; + address: Encoded.ContractAddress; + data: Encoded.ContractBytearray; topics: Array; }> => [{ - address: remoteContract.deployInfo.address as EncodedData<'ct'>, + address: remoteContract.deployInfo.address as Encoded.ContractAddress, data: 'cb_Xfbg4g==', topics: [ '28631352549432199952459007654025571262660118571086898449909844428770770966435', diff --git a/test/integration/contract.ts b/test/integration/contract.ts index 7f25bccfbe..62830c34a9 100644 --- a/test/integration/contract.ts +++ b/test/integration/contract.ts @@ -22,7 +22,7 @@ import { IllegalArgumentError, NodeInvocationError, commitmentHash, decode, encode, DRY_RUN_ACCOUNT, messageToHash, genSalt, UnexpectedTsError, AeSdk, } from '../../src'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded, Encoding } from '../../src/utils/encoder'; import { ContractInstance } from '../../src/contract/aci'; const identityContract = ` @@ -117,7 +117,7 @@ contract Sign = describe('Contract', () => { let aeSdk: AeSdk; - let bytecode: EncodedData<'cb'>; + let bytecode: Encoded.ContractBytearray; let contract: ContractInstance; let deployed: ContractInstance['deployInfo']; @@ -128,7 +128,7 @@ describe('Contract', () => { it('compiles Sophia code', async () => { bytecode = (await aeSdk.compilerApi.compileContract({ code: identityContract, options: {}, - })).bytecode as EncodedData<'cb'>; + })).bytecode as Encoded.ContractBytearray; expect(bytecode).to.satisfy((b: string) => b.startsWith('cb_')); }); @@ -271,7 +271,7 @@ describe('Contract', () => { it('compile', async () => { bytecode = (await aeSdk.compilerApi.compileContract({ code: identityContract, options: {}, - })).bytecode as EncodedData<'cb'>; + })).bytecode as Encoded.ContractBytearray; expect(bytecode.split('_')[0]).to.be.equal('cb'); }); @@ -321,11 +321,11 @@ describe('Contract', () => { }); describe('AENS operation delegation', () => { - let contractId: EncodedData<'ct'>; + let contractId: Encoded.ContractAddress; const name = randomName(15); const salt = genSalt(); - let owner: EncodedData<'ak'>; - let newOwner: EncodedData<'ak'>; + let owner: Encoded.AccountAddress; + let newOwner: Encoded.AccountAddress; let delegationSignature: string; before(async () => { @@ -391,10 +391,10 @@ describe('Contract', () => { }); describe('Oracle operation delegation', () => { - let contractId: EncodedData<'ct'>; - let address: EncodedData<'ak'>; + let contractId: Encoded.ContractAddress; + let address: Encoded.AccountAddress; let oracle: Awaited>; - let oracleId: EncodedData<'ok'>; + let oracleId: Encoded.OracleAddress; let queryObject: Awaited>; let delegationSignature: string; const queryFee = 500000; @@ -406,7 +406,7 @@ describe('Contract', () => { if (contract.deployInfo.address == null) throw new UnexpectedTsError(); contractId = contract.deployInfo.address; address = await aeSdk.address(); - oracleId = encode(decode(address), 'ok'); + oracleId = encode(decode(address), Encoding.OracleAddress); }); it('registers', async () => { @@ -446,7 +446,8 @@ describe('Contract', () => { const response = await contract.methods.respond(oracle.id, queryObject.id, respondSig, r); response.result.returnType.should.be.equal('ok'); // TODO type should be corrected in node api - const queryObject2 = await aeSdk.getQueryObject(oracle.id, queryObject.id as EncodedData<'oq'>); + const queryObject2 = await aeSdk + .getQueryObject(oracle.id, queryObject.id as Encoded.OracleQueryId); queryObject2.decodedResponse.should.be.equal(r); }); }); diff --git a/test/integration/ga.ts b/test/integration/ga.ts index 09bf4da4b2..56ebc2bcff 100644 --- a/test/integration/ga.ts +++ b/test/integration/ga.ts @@ -21,7 +21,7 @@ import { getSdk } from '.'; import { AeSdk, Tag, genSalt, generateKeyPair, unpackTx, } from '../../src'; -import { encode, EncodedData } from '../../src/utils/encoder'; +import { encode, Encoded, Encoding } from '../../src/utils/encoder'; import MemoryAccount from '../../src/account/Memory'; import { ContractInstance } from '../../src/contract/aci'; @@ -40,7 +40,7 @@ const authContractSource = `contract BlindAuth = `; describe('Generalized Account', () => { let aeSdk: AeSdk; - let gaAccountAddress: EncodedData<'ak'>; + let gaAccountAddress: Encoded.AccountAddress; let authContract: ContractInstance; before(async () => { @@ -79,7 +79,10 @@ describe('Generalized Account', () => { it('buildAuthTxHash generates a proper hash', async () => { const { rawTx } = await aeSdk .spend(10000, publicKey, { authData: { source: authContractSource, args: [genSalt()] } }); - const spendTx = encode(unpackTx(rawTx, Tag.SignedTx).tx.encodedTx.tx.tx.tx.encodedTx.rlpEncoded, 'tx'); + const spendTx = encode( + unpackTx(rawTx, Tag.SignedTx).tx.encodedTx.tx.tx.tx.encodedTx.rlpEncoded, + Encoding.Transaction, + ); expect(await aeSdk.buildAuthTxHash(spendTx)).to.be .eql((await authContract.methods.getTxHash()).decodedResult); }); diff --git a/test/integration/index.ts b/test/integration/index.ts index ee1c5a52b8..aa4bd8f14a 100644 --- a/test/integration/index.ts +++ b/test/integration/index.ts @@ -19,11 +19,11 @@ import { AeSdk, generateKeyPair, MemoryAccount, Node, } from '../../src'; import '..'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; export const url = process.env.TEST_URL ?? 'http://localhost:3013'; const compilerUrl = process.env.COMPILER_URL ?? 'http://localhost:3080'; -const publicKey = process.env.PUBLIC_KEY as EncodedData<'ak'> ?? 'ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR'; +const publicKey = process.env.PUBLIC_KEY as Encoded.AccountAddress ?? 'ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR'; const secretKey = process.env.SECRET_KEY ?? 'bf66e1c256931870908a649572ed0257876bb84e3cdf71efb12f56c7335fad54d5cf08400e988222f26eb4b02c8f89077457467211a6e6d955edb70749c6a33b'; export const networkId = process.env.TEST_NETWORK_ID ?? 'ae_devnet'; export const ignoreVersion = process.env.IGNORE_VERSION === 'true'; diff --git a/test/integration/oracle.ts b/test/integration/oracle.ts index bc39f2fa4c..3eb351e0c0 100644 --- a/test/integration/oracle.ts +++ b/test/integration/oracle.ts @@ -24,7 +24,7 @@ import { ORACLE_TTL_TYPES, QUERY_FEE, } from '../../src'; import MemoryAccount from '../../src/account/Memory'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; describe('Oracle', () => { let aeSdk: AeSdk; @@ -75,7 +75,7 @@ describe('Oracle', () => { query = await oracle.getQuery(query.id); expect(query.decodedResponse).to.be.equal(queryResponse); - expect(decode(query.response as EncodedData<'or'>).toString()).to.be.equal(queryResponse); + expect(decode(query.response as Encoded.OracleResponse).toString()).to.be.equal(queryResponse); }); it('Poll for response', async () => { diff --git a/test/integration/paying-for.ts b/test/integration/paying-for.ts index cc0732690c..d6ed47c24e 100644 --- a/test/integration/paying-for.ts +++ b/test/integration/paying-for.ts @@ -23,7 +23,7 @@ import { AeSdk, generateKeyPair, MemoryAccount, Tag, UnexpectedTsError, } from '../../src'; import { ContractInstance } from '../../src/contract/aci'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; describe('Paying for transaction of another account', () => { let aeSdk: AeSdk; @@ -63,7 +63,7 @@ describe('Paying for transaction of another account', () => { entrypoint init(x: int): state = { value = x } entrypoint getValue(): int = state.value stateful entrypoint setValue(x: int) = put(state{ value = x })`; - let contractAddress: EncodedData<'ct'>; + let contractAddress: Encoded.ContractAddress; let aeSdkNotPayingFee: any; let payingContract: ContractInstance; diff --git a/test/integration/rpc.ts b/test/integration/rpc.ts index af36c0b24e..792f83d249 100644 --- a/test/integration/rpc.ts +++ b/test/integration/rpc.ts @@ -51,7 +51,7 @@ import { getSdk, ignoreVersion, networkId, url, } from '.'; import { Accounts, Network } from '../../src/aepp-wallet-communication/rpc/types'; -import { EncodedData, EncodingType } from '../../src/utils/encoder'; +import { Encoded, Encoding } from '../../src/utils/encoder'; const WindowPostMessageFake = ( name: string, @@ -99,7 +99,7 @@ describe('Aepp<->Wallet', function aeppWallet() { const handlerReject = (): void => { throw new Error('test reject'); }; const handlerRejectPromise = async (): Promise => { throw new Error('test reject'); }; let account: AccountBase; - let accountAddress: EncodedData<'ak'>; + let accountAddress: Encoded.AccountAddress; describe('New RPC Wallet-AEPP: AEPP node', () => { const keypair = generateKeyPair(); @@ -321,7 +321,7 @@ describe('Aepp<->Wallet', function aeppWallet() { }); const res = await aepp.send(tx); if (res.tx?.payload == null || res.blockHeight == null) throw new UnexpectedTsError(); - decode(res.tx.payload as EncodedData).toString().should.be.equal('zerospend2'); + decode(res.tx.payload as Encoded.Any).toString().should.be.equal('zerospend2'); res.blockHeight.should.be.a('number'); }); @@ -383,7 +383,8 @@ describe('Aepp<->Wallet', function aeppWallet() { it('Receive update for wallet select account', async () => { if (aepp._accounts == null) throw new UnexpectedTsError(); - const connectedAccount = Object.keys(aepp._accounts.connected)[0] as EncodedData<'ak'>; + const connectedAccount = Object + .keys(aepp._accounts.connected)[0] as Encoded.AccountAddress; const accountsPromise = new Promise((resolve) => { aepp.onAddressChange = resolve; }); @@ -534,7 +535,7 @@ describe('Aepp<->Wallet', function aeppWallet() { }); const res = await aepp.send(tx); if (res.tx?.payload == null || res.blockHeight == null) throw new UnexpectedTsError(); - decode(res.tx.payload as EncodedData).toString().should.be.equal('zerospend2'); + decode(res.tx.payload as Encoded.Any).toString().should.be.equal('zerospend2'); res.blockHeight.should.be.a('number'); }); diff --git a/test/integration/transaction.ts b/test/integration/transaction.ts index be5c21e408..5da122633f 100644 --- a/test/integration/transaction.ts +++ b/test/integration/transaction.ts @@ -23,14 +23,14 @@ import { commitmentHash, oracleQueryId, decode, encode, ORACLE_TTL_TYPES, Tag, AE_AMOUNT_FORMATS, } from '../../src'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded, Encoding } from '../../src/utils/encoder'; const nonce = 1; const nameTtl = 1; const clientTtl = 1; const amount = 0; -const senderId: EncodedData<'ak'> = 'ak_2iBPH7HUz3cSDVEUWiHg76MZJ6tZooVNBmmxcgVK6VV8KAE688'; -const recipientId: EncodedData<'ak'> = 'ak_2iBPH7HUz3cSDVEUWiHg76MZJ6tZooVNBmmxcgVK6VV8KAE688'; +const senderId: Encoded.AccountAddress = 'ak_2iBPH7HUz3cSDVEUWiHg76MZJ6tZooVNBmmxcgVK6VV8KAE688'; +const recipientId: Encoded.AccountAddress = 'ak_2iBPH7HUz3cSDVEUWiHg76MZJ6tZooVNBmmxcgVK6VV8KAE688'; const name = 'test123test.chain'; const nameId = 'nm_2sFnPHi5ziAqhdApSpRBsYdomCahtmk3YGNZKYUTtUNpVSMccC'; const nameFee = '1000000000000000000000'; @@ -60,7 +60,7 @@ const commitmentId = commitmentHash(name, nameSalt); describe('Transaction', () => { let aeSdk: AeSdk; const address = 'ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR'; - const oracleId = encode(decode(address), 'ok'); + const oracleId = encode(decode(address), Encoding.OracleAddress); let contract: any; before(async () => { diff --git a/test/unit/crypto.ts b/test/unit/crypto.ts index 938a64a5c8..6f91faa10f 100644 --- a/test/unit/crypto.ts +++ b/test/unit/crypto.ts @@ -20,13 +20,13 @@ import { describe, it } from 'mocha'; import { assert, expect } from 'chai'; import * as Crypto from '../../src/utils/crypto'; import { buildTxHash, unpackTx, decode } from '../../src'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; // These keys are fixations for the encryption lifecycle tests and will // not be used for signing const privateKeyAsHex = '4d881dd1917036cc231f9881a0db978c8899dd76a817252418606b02bf6ab9d22378f892b7cc82c2d2739e994ec9953aa36461f1eb5a4a49a5b0de17b3d23ae8'; const privateKey = Buffer.from(privateKeyAsHex, 'hex'); -const publicKeyWithPrefix: EncodedData<'ak'> = 'ak_Gd6iMVsoonGuTF8LeswwDDN2NF5wYHAoTRtzwdEcfS32LWoxm'; +const publicKeyWithPrefix: Encoded.AccountAddress = 'ak_Gd6iMVsoonGuTF8LeswwDDN2NF5wYHAoTRtzwdEcfS32LWoxm'; const publicKey = decode(publicKeyWithPrefix); const txBinaryAsArray = [ diff --git a/test/unit/hd-wallet.ts b/test/unit/hd-wallet.ts index da4f3597ef..10fe609c34 100644 --- a/test/unit/hd-wallet.ts +++ b/test/unit/hd-wallet.ts @@ -23,7 +23,9 @@ import { getSaveHDWalletAccounts, DerivationError, } from '../../src'; -import { encode, decode, EncodedData } from '../../src/utils/encoder'; +import { + encode, decode, Encoded, Encoding, +} from '../../src/utils/encoder'; import { concatBuffers } from '../../src/utils/other'; describe('hd wallet', () => { @@ -62,7 +64,7 @@ describe('hd wallet', () => { expect(accounts).to.eql(testAccounts.map((acc) => ({ secretKey: acc.secretKey, - publicKey: encode(Buffer.from(acc.publicKey, 'hex'), 'ak'), + publicKey: encode(Buffer.from(acc.publicKey, 'hex'), Encoding.AccountAddress), }))); })); @@ -165,7 +167,7 @@ describe('hd wallet', () => { it('get HdWalletAccount from seed', () => { const wallet = getHdWalletAccountFromSeed(testMnemonicSeed, 0); - decode(wallet.publicKey as EncodedData<'ak'>); + decode(wallet.publicKey as Encoded.AccountAddress); }); it('Derive child with invalid path', () => { diff --git a/test/unit/memory-account.ts b/test/unit/memory-account.ts index 493a21045c..659ce04020 100644 --- a/test/unit/memory-account.ts +++ b/test/unit/memory-account.ts @@ -20,7 +20,7 @@ import { describe, it } from 'mocha'; import { expect } from 'chai'; import MemoryAccount from '../../src/account/Memory'; import { generateKeyPair, InvalidKeypairError, DecodeError } from '../../src'; -import { EncodedData } from '../../src/utils/encoder'; +import { Encoded } from '../../src/utils/encoder'; const testAcc = generateKeyPair(); @@ -32,7 +32,7 @@ describe('MemoryAccount', () => { }); it('Fail on invalid publicKey', async () => { - expect(() => new MemoryAccount({ keypair: { publicKey: ' ' as EncodedData<'ak'>, secretKey: testAcc.secretKey } })) + expect(() => new MemoryAccount({ keypair: { publicKey: ' ' as Encoded.AccountAddress, secretKey: testAcc.secretKey } })) .to.throw(DecodeError, 'Encoded string missing payload'); }); diff --git a/test/unit/tx.ts b/test/unit/tx.ts index 583d9a1af5..46e5f7c224 100644 --- a/test/unit/tx.ts +++ b/test/unit/tx.ts @@ -30,6 +30,7 @@ import { NAME_BID_RANGES, Tag, SchemaNotFoundError, } from '../../src'; +import { Encoding } from '../../src/utils/encoder'; describe('Tx', () => { it('reproducible commitment hashes can be generated', async () => { @@ -92,9 +93,11 @@ describe('Tx', () => { }); describe('encode', () => { - it('encodes base64check', () => expect(encode(payload, 'ba')).to.be.equal('ba_AQIq9Y55kw==')); + it('encodes base64check', () => expect(encode(payload, Encoding.Bytearray)) + .to.be.equal('ba_AQIq9Y55kw==')); - it('encodes base58check', () => expect(encode(payload, 'nm')).to.be.equal('nm_3DZUwMat2')); + it('encodes base58check', () => expect(encode(payload, Encoding.Name)) + .to.be.equal('nm_3DZUwMat2')); }); describe('getDefaultPointerKey', () => { @@ -103,7 +106,7 @@ describe('Tx', () => { }); it('Deserialize tx: invalid tx VSN', () => { - const tx = encode(rlpEncode([10, 99]), 'tx'); + const tx = encode(rlpEncode([10, 99]), Encoding.Transaction); expect(() => unpackTx(tx)) .to.throw(SchemaNotFoundError, `Transaction deserialization not implemented for tag ${10} version ${99}`); });