From 3fc6f6d1dc51c717f87e4ae1e882ca7c943fc3ef Mon Sep 17 00:00:00 2001 From: martinkaintas Date: Thu, 16 Jun 2022 13:27:56 +0300 Subject: [PATCH] refactor(tests)!: migrate remaining tests ts BREAKING CHANGE: `computeBidFee` accepts `startFee`, `increment` as options --- src/AeSdkBase.ts | 11 +-- src/account/base.ts | 2 +- src/account/memory.ts | 2 +- src/account/rpc.ts | 2 +- src/ae/aens.ts | 24 +++-- src/ae/oracle.ts | 6 +- src/chain.ts | 12 +-- src/contract/aci.ts | 49 +++++++--- src/contract/ga.ts | 4 +- src/tx/builder/field-types.ts | 2 +- src/tx/builder/helpers.ts | 10 ++- src/tx/index.ts | 20 +++-- src/tx/validator.ts | 2 +- src/utils/errors.ts | 8 +- test/integration/{accounts.js => accounts.ts} | 44 +++++---- test/integration/{aens.js => aens.ts} | 30 +++++-- test/integration/{chain.js => chain.ts} | 59 ++++++------ test/integration/channel.ts | 4 +- .../{contract-aci.js => contract-aci.ts} | 90 +++++++++++-------- test/integration/{contract.js => contract.ts} | 65 +++++++------- test/integration/{ga.js => ga.ts} | 15 ++-- test/integration/{oracle.js => oracle.ts} | 30 ++++--- .../{paying-for.js => paying-for.ts} | 25 +++--- test/integration/txVerification.ts | 13 +-- 24 files changed, 313 insertions(+), 216 deletions(-) rename test/integration/{accounts.js => accounts.ts} (87%) rename test/integration/{aens.js => aens.ts} (84%) rename test/integration/{chain.js => chain.ts} (76%) rename test/integration/{contract-aci.js => contract-aci.ts} (91%) rename test/integration/{contract.js => contract.ts} (91%) rename test/integration/{ga.js => ga.ts} (87%) rename test/integration/{oracle.js => oracle.ts} (75%) rename test/integration/{paying-for.js => paying-for.ts} (82%) diff --git a/src/AeSdkBase.ts b/src/AeSdkBase.ts index 0cc7cc022a..627631e5a7 100644 --- a/src/AeSdkBase.ts +++ b/src/AeSdkBase.ts @@ -53,10 +53,11 @@ function getValueOrErrorProxy (valueCb: () => Value): Valu * available. */ class AeSdkBase { - _options = { - denomination: AE_AMOUNT_FORMATS.AETTOS, - amount: AMOUNT - } + _options: { + denomination: AE_AMOUNT_FORMATS + amount: number + [key: string]: any + } = { denomination: AE_AMOUNT_FORMATS.AETTOS, amount: AMOUNT } pool: Map = new Map() selectedNodeName?: string @@ -190,7 +191,7 @@ class AeSdkBase { } async sign ( - data: string, { onAccount, ...options }: { onAccount?: Account } = {} + data: string | Uint8Array, { onAccount, ...options }: { onAccount?: Account } = {} ): Promise { return await this._resolveAccount(onAccount).sign(data, options) } diff --git a/src/account/base.ts b/src/account/base.ts index 5fb55ad8b3..c6319daed5 100644 --- a/src/account/base.ts +++ b/src/account/base.ts @@ -104,7 +104,7 @@ export default abstract class AccountBase { * @param options - Options * @returns Signed data blob */ - abstract sign (data: string | Buffer, options?: any): Promise + abstract sign (data: string | Uint8Array, options?: any): Promise /** * Obtain account address diff --git a/src/account/memory.ts b/src/account/memory.ts index e2930941c5..a6535e5f5c 100644 --- a/src/account/memory.ts +++ b/src/account/memory.ts @@ -72,7 +72,7 @@ export default class AccountMemory extends AccountBase { }) } - async sign (data: string): Promise { + async sign (data: string | Uint8Array): Promise { if (this.isGa) throw new InvalidKeypairError('You are trying to sign data using generalized account without keypair') return sign(data, secrets.get(this).secretKey) } diff --git a/src/account/rpc.ts b/src/account/rpc.ts index 97edaaef69..67afa7d9d2 100644 --- a/src/account/rpc.ts +++ b/src/account/rpc.ts @@ -23,7 +23,7 @@ export default class AccountRpc extends AccountBase { this._address = address } - async sign (data: string | Buffer, options?: any): Promise { + async sign (data: string | Uint8Array, options?: any): Promise { throw new NotImplementedError('RAW signing using wallet') } diff --git a/src/ae/aens.ts b/src/ae/aens.ts index 0929e58a45..4f4e88bf4a 100644 --- a/src/ae/aens.ts +++ b/src/ae/aens.ts @@ -34,6 +34,7 @@ import { AensName, getName, height } from '../chain' import { _buildTx, BuildTxOptions } from '../tx' import { TransformNodeType } from '../node' import { NameEntry } from '../apis/node' +import AccountBase from '../account/base' interface KeyPointers { [key: string]: string | Buffer @@ -101,7 +102,7 @@ export async function aensRevoke ( */ export async function aensUpdate ( name: AensName, - pointers: KeyPointers = {}, + pointers: KeyPointers, { extendPointers, ...options }: { extendPointers?: boolean } & Parameters[1] & BuildTxOptions & { clientTtl?: number, nameTtl?: number } @@ -109,7 +110,7 @@ export async function aensUpdate ( const allPointers = { ...extendPointers === true && Object.fromEntries( (await getName(name, options)).pointers - .map(({ key, id }: {key: string, id: string}) => [key, id]) + .map(({ key, id }: { key: string, id: string }) => [key, id]) ), ...pointers } @@ -196,16 +197,21 @@ export async function aensQuery ( ttl: number update: ( pointers: KeyPointers, - options: Parameters[1] + options?: Omit[1], 'onNode' | 'onCompiler' | 'onAccount'> & { + onAccount?: AccountBase + } ) => ReturnType & ReturnType transfer: ( account: EncodedData<'ak'>, - options: Parameters[1] + options?: Parameters[1] ) => ReturnType & ReturnType - revoke: (options: Parameters[1]) => ReturnType + revoke: (options?: Omit[1], 'onNode' | 'onCompiler' | 'onAccount'> & { + onAccount?: AccountBase + } + ) => ReturnType extendTtl: ( nameTtl: number, - options: Parameters[1] + options?: Omit[1], 'onNode' | 'onCompiler' | 'onAccount'> ) => ReturnType & ReturnType } >> { @@ -318,7 +324,7 @@ export async function aensPreclaim ( height: number salt: number commitmentId: string - claim: (opts: Parameters[2]) => ReturnType + claim: (opts?: Parameters[2]) => ReturnType } >> { const _salt = salt() @@ -363,8 +369,8 @@ export async function aensPreclaim ( */ export async function aensBid ( name: AensName, - nameFee: BigNumber, - options: Omit[2], 'nameFee' | 'VSN'> + nameFee: number | string | BigNumber, + options: Omit[2], 'nameFee'> ): ReturnType { return await aensClaim(name, 0, { ...options, nameFee }) } diff --git a/src/ae/oracle.ts b/src/ae/oracle.ts index dc5e80820f..ec91facfac 100644 --- a/src/ae/oracle.ts +++ b/src/ae/oracle.ts @@ -58,7 +58,7 @@ export async function getOracleObject ( id: EncodedData<'ok'> queries: OracleQueries // TODO: replace getOracleObject with a class - pollQueries: Function + pollQueries: (cb: Parameters[1]) => ReturnType postQuery: Function respondToQuery: Function extendOracle: Function @@ -141,9 +141,9 @@ export async function getQueryObject ( Awaited> & { decodedQuery: string decodedResponse: string - respond: (response: string, options: Parameters[3]) => + respond: (response: string, options?: Parameters[3]) => ReturnType - pollForResponse: (options: Parameters[2]) => + pollForResponse: (options?: Parameters[2]) => ReturnType } > { diff --git a/src/chain.ts b/src/chain.ts index 6d00f4919d..3848cd767c 100644 --- a/src/chain.ts +++ b/src/chain.ts @@ -79,11 +79,7 @@ export async function sendTransaction ( if (validation.length > 0) { const message = 'Transaction verification errors: ' + validation.map((v: { message: string }) => v.message).join(', ') - throw Object.assign(new InvalidTxError(message), { - code: 'TX_VERIFICATION_ERROR', - validation, - transaction: tx - }) + throw new InvalidTxError(message, validation, tx) } } @@ -157,7 +153,7 @@ export async function waitForTxConfirm ( * @param options.onNode - Node to use */ export async function getAccount ( - address: EncodedData<'ak'>, + address: EncodedData<'ak' | 'ct'>, { height, hash, onNode }: { height?: number, hash?: EncodedData<'kh' | 'mh'>, onNode: Node } ): Promise> { @@ -176,9 +172,9 @@ 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'>, + address: EncodedData<'ak' | 'ct'>, { format = AE_AMOUNT_FORMATS.AETTOS, ...options }: - { format: AE_AMOUNT_FORMATS } & Parameters[1] + { format?: AE_AMOUNT_FORMATS } & Parameters[1] ): Promise { const { balance } = await getAccount(address, options).catch(() => ({ balance: 0n })) diff --git a/src/contract/aci.ts b/src/contract/aci.ts index 1b97d16f0c..37925ebcf6 100644 --- a/src/contract/aci.ts +++ b/src/contract/aci.ts @@ -43,7 +43,7 @@ import { Aci as BaseAci } from '../apis/compiler' import Compiler from './compiler' import Node from '../node' import { - getAccount, getContract, getContractByteCode, getKeyBlock, resolveName, txDryRun + getAccount, getContract, getContractByteCode, getKeyBlock, resolveName, txDryRun, AensName } from '../chain' import AccountBase from '../account/base' @@ -113,10 +113,29 @@ export interface ContractInstance { options: any compile: (options?: {}) => Promise> _estimateGas: (name: string, params: any[], options: object) => Promise - deploy: (params: any[], options: object) => Promise - call: (fn: string, params?: any[], options?: {}) => Promise - decodeEvents: (events: Event[], { omitUnknown, ...opt }: { - omitUnknown?: boolean}) => DecodedEvent[] + deploy: (params?: any[], options?: object) => Promise + call: (fn: string, params?: any[], options?: {}) => Promise<{ + hash: string + tx: any + txData: TxData + rawTx: string + result: { + callerId: EncodedData<'ak'> + callerNonce: number + contractId: EncodedData<'ct'> + gasPrice: number + gasUsed: number + height: number + log: any[] + returnType: string + returnValue: string + } + decodedResult: any + decodedEvents: DecodedEvent[] + }> + decodeEvents: ( + events: Event[], options?: { omitUnknown?: boolean, contractAddressToName?: any } + ) => DecodedEvent[] methods: any } @@ -158,9 +177,10 @@ export default async function getContractInstance ({ source?: string bytecode?: EncodedData<'cb'> aci?: Aci - contractAddress?: EncodedData<'ct'> + contractAddress?: EncodedData<'ct'> | AensName fileSystem?: Record validateBytecode?: boolean + [key: string]: any }): Promise { if (_aci == null && source != null) { // TODO: should be fixed when the compiledAci interface gets updated @@ -200,13 +220,12 @@ export default async function getContractInstance ({ ...otherOptions }, compile: async function (_options?: {}): Promise {}, - _estimateGas: async function (_name: string, _params: any[], _options: object): Promise {}, - deploy: async function (_params: any[], _options: any): Promise {}, + _estimateGas: async function ( + _name: string, _params: any[], _options: object + ): Promise {}, + deploy: async function (_params?: any[], _options?: any): Promise {}, call: async function (_fn: string, _params?: any[], _options?: {}): Promise {}, - decodeEvents ( - _events: Event[], - { omitUnknown, ...opt }: { omitUnknown?: boolean } - ): any {}, + decodeEvents (_events: Event[], options?: { omitUnknown?: boolean }): any {}, methods: undefined } @@ -259,7 +278,8 @@ export default async function getContractInstance ({ const handleCallError = ( { returnType, returnValue }: { returnType: ContractCallReturnType - returnValue: EncodedData}, + returnValue: EncodedData + }, transaction: string): void => { let message: string switch (returnType) { @@ -297,6 +317,7 @@ export default async function getContractInstance ({ ): Promise => { const opt = { ...instance.options, ...options } if (instance.bytecode == null) await instance.compile(opt) + // @ts-expect-error if (opt.callStatic === true) return await instance.call('init', params, opt) if (instance.deployInfo.address != null) throw new DuplicateContractError() @@ -446,7 +467,7 @@ export default async function getContractInstance ({ */ instance.decodeEvents = ( events: Event[], - { omitUnknown, ...opt }: {omitUnknown?: boolean} = {} + { omitUnknown, ...opt }: { omitUnknown?: boolean } = {} ): DecodedEvent[] => events .map(event => { const topics = event.topics.map((t: string | number) => BigInt(t)) diff --git a/src/contract/ga.ts b/src/contract/ga.ts index cba1bd13fe..71ad9a7e32 100644 --- a/src/contract/ga.ts +++ b/src/contract/ga.ts @@ -59,8 +59,8 @@ export async function createGeneralizedAccount ( source: string, args: any[], { onAccount, onCompiler, onNode, ...options }: - { onAccount: AccountBase, onCompiler: Compiler, onNode: Node } - & BuildTxOptions + { onAccount: AccountBase, onCompiler: Compiler, onNode: Node, gasLimit?: number } + & BuildTxOptions & Parameters[1] ): Promise diff --git a/src/tx/builder/field-types.ts b/src/tx/builder/field-types.ts index d4fb2c8f6c..58b63cb37c 100644 --- a/src/tx/builder/field-types.ts +++ b/src/tx/builder/field-types.ts @@ -61,7 +61,7 @@ export class NameFee extends Field { * @param txFields - Transaction fields * @param txFields.name - AENS Name in transaction */ - static serialize (value: Int, { name }: { name: AensName }): Buffer { + static serialize (value: Int | undefined, { name }: { name: AensName }): Buffer { const minNameFee = getMinimumNameFee(name) value ??= minNameFee if (minNameFee.gt(value)) { diff --git a/src/tx/builder/helpers.ts b/src/tx/builder/helpers.ts index 9a373f9ef3..cd754f6aa4 100644 --- a/src/tx/builder/helpers.ts +++ b/src/tx/builder/helpers.ts @@ -209,17 +209,19 @@ export function getMinimumNameFee (name: AensName): BigNumber { * Compute bid fee for AENS auction * * @param name - the AENS name to get the fee for - * @param startFee - Auction start fee - * @param increment - Bid multiplier(In percentage, must be between 0 and 1) + * @param options - Options + * @param options.startFee - Auction start fee + * @param options.increment - Bid multiplier(In percentage, must be between 0 and 1) * @returns Bid fee */ export function computeBidFee ( name: AensName, - startFee: number | string | null, - increment: number = NAME_FEE_BID_INCREMENT + { startFee, increment = NAME_FEE_BID_INCREMENT }: + { startFee?: number | string | BigNumber, increment?: number } = {} ): BigNumber { if (!(Number(increment) === increment && increment % 1 !== 0)) throw new IllegalBidFeeError(`Increment must be float. Current increment ${increment}`) if (increment < NAME_FEE_BID_INCREMENT) throw new IllegalBidFeeError(`minimum increment percentage is ${NAME_FEE_BID_INCREMENT}`) + // FIXME: increment should be used somehow here return ceil( new BigNumber(startFee ?? getMinimumNameFee(name)) .times(new BigNumber(NAME_FEE_BID_INCREMENT).plus(1)) diff --git a/src/tx/index.ts b/src/tx/index.ts index f8f197140d..8d2b53f281 100644 --- a/src/tx/index.ts +++ b/src/tx/index.ts @@ -46,9 +46,16 @@ export type BuildTxOptions = // TODO: find a better name or rearrange methods export async function _buildTx ( txType: TxType, - { denomination, ..._params }: + { denomination, absoluteTtl, ..._params }: Omit>[0], 'fee' | 'nonce' | 'ttl' | 'ctVersion' | 'abiVersion'> - & { onNode: Node, fee?: Int, nonce?: number, ttl?: number, denomination?: AE_AMOUNT_FORMATS } + & { + onNode: Node + fee?: Int + nonce?: number + ttl?: number + denomination?: AE_AMOUNT_FORMATS + absoluteTtl?: boolean + } & (TxType extends TX_TYPE.oracleExtend | TX_TYPE.oracleResponse ? { callerId: EncodedData<'ak'> } : {}) & (TxType extends TX_TYPE.contractCreate | TX_TYPE.gaAttach ? { ctVersion?: CtVersion } : {}) & (TxType extends TX_TYPE.contractCall | TX_TYPE.oracleRegister @@ -109,7 +116,9 @@ export async function _buildTx ( const senderId = params[senderKey] // TODO: do this check on TypeScript level if (senderId == null) throw new InvalidTxParamsError(`Transaction field ${senderKey} is missed`) - const extraParams = await prepareTxParams(txType, { ...params, senderId, denomination }) + const extraParams = await prepareTxParams( + txType, { ...params, senderId, denomination, absoluteTtl } + ) return syncBuildTx({ ...params, ...extraParams } as any, txType, { denomination }).tx } @@ -161,7 +170,8 @@ export async function prepareTxParams ( vsn, strategy, denomination, - onNode + onNode, + ...txParams }: Pick & { senderId: EncodedData<'ak'> vsn?: number @@ -182,6 +192,6 @@ export async function prepareTxParams ( const fee = f != null ? new BigNumber(f) - : calculateMinFee(txType, { params: { ...arguments[1], nonce, ttl }, vsn, denomination }) + : calculateMinFee(txType, { params: { ...txParams, senderId, nonce, ttl }, vsn, denomination }) return { fee, ttl, nonce } } diff --git a/src/tx/validator.ts b/src/tx/validator.ts index 03848c926b..c66360248f 100644 --- a/src/tx/validator.ts +++ b/src/tx/validator.ts @@ -17,7 +17,7 @@ interface Account { nonce: number } -interface ValidatorResult { +export interface ValidatorResult { message: string key: string checkedKeys: string[] diff --git a/src/utils/errors.ts b/src/utils/errors.ts index aa64cf9fc7..a86cf58bd9 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,4 +1,6 @@ import BigNumber from 'bignumber.js' +import { ValidatorResult } from '../tx/validator' +import { EncodedData } from './encoder' /** * aepp-sdk originated error @@ -694,9 +696,13 @@ export class InvalidSignatureError extends TransactionError { * @category exception */ export class InvalidTxError extends TransactionError { - constructor (message: string) { + validation: ValidatorResult[] + transaction: EncodedData<'tx'> + constructor (message: string, validation: ValidatorResult[], transaction: EncodedData<'tx'>) { super(message) this.name = 'InvalidTxError' + this.validation = validation + this.transaction = transaction } } diff --git a/test/integration/accounts.js b/test/integration/accounts.ts similarity index 87% rename from test/integration/accounts.js rename to test/integration/accounts.ts index 391b206ea7..f26e494200 100644 --- a/test/integration/accounts.js +++ b/test/integration/accounts.ts @@ -17,7 +17,7 @@ import { describe, it, before } from 'mocha' import { expect } from 'chai' -import { getSdk, BaseAe, networkId } from './' +import { getSdk, BaseAe, networkId } from '.' import { generateKeyPair } from '../../src/utils/crypto' import BigNumber from 'bignumber.js' import MemoryAccount from '../../src/account/memory' @@ -27,11 +27,13 @@ import { TypeError, ArgumentError, InvalidKeypairError, - InvalidTxParamsError + InvalidTxParamsError, + UnexpectedTsError } from '../../src/utils/errors' +import { AeSdk } from '../../src' describe('Accounts', function () { - let aeSdk, aeSdkWithoutAccount + let aeSdk: AeSdk, aeSdkWithoutAccount: AeSdk before(async function () { aeSdk = await getSdk() @@ -42,7 +44,7 @@ describe('Accounts', function () { const receiver = receiverKey.publicKey describe('fails on unknown keypairs', () => { - let wallet + let wallet: any before(async function () { wallet = await getSdk() @@ -65,16 +67,22 @@ describe('Accounts', function () { await aeSdk.getBalance(await aeSdk.address()).should.eventually.be.a('string') }) - describe('transferFunds', async () => { - const spend = async fraction => { + describe('transferFunds', () => { + const spend = async (fraction: number): Promise<{ + balanceBefore: BigNumber + balanceAfter: BigNumber + amount: BigNumber + fee: BigNumber + }> => { const balanceBefore = new BigNumber(await aeSdk.getBalance(await aeSdk.address())) const { tx } = await aeSdk.transferFunds(fraction, receiver) const balanceAfter = new BigNumber(await aeSdk.getBalance(await aeSdk.address())) + if (tx == null || tx.amount == null) throw new UnexpectedTsError() return { balanceBefore, balanceAfter, - amount: new BigNumber(tx.amount), - fee: new BigNumber(tx.fee) + amount: new BigNumber(tx.amount.toString()), + fee: new BigNumber(tx.fee.toString()) } } @@ -108,12 +116,14 @@ describe('Accounts', function () { it('spends coins', async () => { const ret = await aeSdk.spend(1, receiver) ret.should.have.property('tx') + if (ret.tx == null) throw new UnexpectedTsError() ret.tx.should.include({ amount: 1n, recipientId: receiver }) }) it('spends coins in AE format', async () => { const ret = await aeSdk.spend(1, receiver, { denomination: AE_AMOUNT_FORMATS.AE }) ret.should.have.property('tx') + if (ret.tx == null) throw new UnexpectedTsError() ret.tx.should.include({ amount: 10n ** 18n, recipientId: receiver }) }) @@ -121,11 +131,12 @@ describe('Accounts', function () { const bigAmount = 10n ** 31n + 10n ** 17n const genesis = await BaseAe({ networkId }) const receiverWallet = generateKeyPair() - const ret = await genesis.spend(bigAmount, receiverWallet.publicKey) + const ret = await genesis.spend(bigAmount.toString(), receiverWallet.publicKey) const balanceAfter = await aeSdk.getBalance(receiverWallet.publicKey) balanceAfter.should.be.equal(bigAmount.toString()) ret.should.have.property('tx') + if (ret.tx == null) throw new UnexpectedTsError() ret.tx.should.include({ amount: bigAmount, recipientId: receiverWallet.publicKey }) }) @@ -133,16 +144,14 @@ describe('Accounts', function () { const h = await aeSdk.height() await aeSdk.awaitHeight(h + 3) const spend = await aeSdk.spend(123, 'ak_DMNCzsVoZnpV5fe8FTQnNsTfQ48YM5C3WbHPsJyHjAuTXebFi') + if (spend.blockHeight == null || spend.tx?.amount == null) throw new UnexpectedTsError() await aeSdk.awaitHeight(spend.blockHeight + 2) const accountAfterSpend = await aeSdk.getAccount(await aeSdk.address()) const accountBeforeSpendByHash = await aeSdk.getAccount( await aeSdk.address(), { height: spend.blockHeight - 1 } ) - new BigNumber(accountBeforeSpendByHash.balance) - .minus(new BigNumber(accountAfterSpend.balance)) - .toString() - .should.be - .equal(`${spend.tx.fee + spend.tx.amount}`) + expect(accountBeforeSpendByHash.balance - accountAfterSpend.balance).to.be + .equal(spend.tx.fee + spend.tx.amount) }) describe('Make operation on specific account without changing of current account', () => { @@ -152,12 +161,13 @@ describe('Accounts', function () { const onAccount = accounts.find(acc => acc !== current) const { tx } = await aeSdk.spend(1, await aeSdk.address(), { onAccount }) + if (tx?.senderId == null) throw new UnexpectedTsError() tx.senderId.should.be.equal(onAccount) current.should.be.equal(current) }) it('Fail on invalid account', async () => { - await expect(aeSdk.spend(1, await aeSdk.address(), { onAccount: 1 })) + await expect(aeSdk.spend(1, await aeSdk.address(), { onAccount: 1 as any })) .to.be.rejectedWith( TypeError, 'Account should be an address (ak-prefixed string), keypair, or instance of AccountBase, got 1 instead') @@ -190,8 +200,8 @@ describe('Accounts', function () { const signature = await memoryAccount.sign(data) const sigUsingKeypair = await aeSdk.sign(data, { onAccount: keypair }) const sigUsingMemoryAccount = await aeSdk.sign(data, { onAccount: memoryAccount }) - signature.toString('hex').should.be.equal(sigUsingKeypair.toString('hex')) - signature.toString('hex').should.be.equal(sigUsingMemoryAccount.toString('hex')) + signature.toString().should.be.equal(sigUsingKeypair.toString()) + signature.toString().should.be.equal(sigUsingMemoryAccount.toString()) // address const addressFromKeypair = await aeSdk.address({ onAccount: keypair }) const addressFrommemoryAccount = await aeSdk.address({ onAccount: memoryAccount }) diff --git a/test/integration/aens.js b/test/integration/aens.ts similarity index 84% rename from test/integration/aens.js rename to test/integration/aens.ts index deb0b8f91e..2597e8efdc 100644 --- a/test/integration/aens.js +++ b/test/integration/aens.ts @@ -17,15 +17,16 @@ import { describe, it, before } from 'mocha' import { expect } from 'chai' -import { getSdk } from './' +import { getSdk } from '.' import { randomName } from '../utils' import { generateKeyPair } from '../../src/utils/crypto' import { buildContractId, computeAuctionEndBlock, computeBidFee } from '../../src/tx/builder/helpers' -import { AensPointerContextError } from '../../src/utils/errors' +import { AensPointerContextError, UnexpectedTsError } from '../../src/utils/errors' import { pause } from '../../src/utils/other' +import { AeSdk } from '../../src' describe('Aens', function () { - let aeSdk + let aeSdk: AeSdk const account = generateKeyPair() const name = randomName(13) // 13 name length doesn't trigger auction @@ -39,6 +40,7 @@ describe('Aens', function () { preclaim.should.be.an('object') const claimed = await preclaim.claim() claimed.should.be.an('object') + if (claimed.id == null || claimed.ttl == null) throw new UnexpectedTsError() claimed.id.should.be.a('string') claimed.ttl.should.be.an('number') }) @@ -69,6 +71,7 @@ describe('Aens', function () { const contract = await aeSdk.getContractInstance({ source }) await contract.deploy([]) const nameObject = await aeSdk.aensQuery(name) + if (contract.deployInfo.address == null) throw new UnexpectedTsError() await nameObject.update({ contract_pubkey: contract.deployInfo.address }) const contractByName = await aeSdk.getContractInstance({ source, contractAddress: name }) @@ -95,7 +98,8 @@ describe('Aens', function () { await preclaim.claim() const current = await aeSdk.address() const onAccount = aeSdk.addresses().find(acc => acc !== current) - await aeSdk.aensUpdate(name, onAccount, { onAccount, blocks: 1 }).should.eventually.be.rejected + if (onAccount == null) throw new UnexpectedTsError() + await aeSdk.aensUpdate(name, {}, { onAccount, blocks: 1 }).should.eventually.be.rejected }) it('updates extending pointers', async () => { @@ -113,15 +117,17 @@ describe('Aens', function () { it('throws error on setting 33 pointers', async () => { const nameObject = await aeSdk.aensQuery(name) const pointers = Object.fromEntries( - new Array(33).fill().map((v, i) => [`pointer-${i}`, address]) + new Array(33).fill(undefined).map((v, i) => [`pointer-${i}`, address]) ) - expect(nameObject.update(pointers)) + await expect(nameObject.update(pointers)) .to.be.rejectedWith('Expected 32 pointers or less, got 33 instead') }) it('Extend name ttl', async () => { const nameObject = await aeSdk.aensQuery(name) - const extendResult = await nameObject.extendTtl(10000) + const extendResult: Awaited> = await nameObject + .extendTtl(10000) + if (extendResult.blockHeight == null) throw new UnexpectedTsError() return extendResult.should.be.deep.include({ ttl: extendResult.blockHeight + 10000 }) @@ -137,6 +143,7 @@ describe('Aens', function () { const claim = await aeSdk.aensQuery(name) const current = await aeSdk.address() const onAccount = aeSdk.addresses().find(acc => acc !== current) + if (onAccount == null) throw new UnexpectedTsError() await claim.transfer(onAccount) const claim2 = await aeSdk.aensQuery(name) @@ -147,7 +154,9 @@ describe('Aens', function () { it('revoke names', async () => { const current = await aeSdk.address() - const onAccount = aeSdk.accounts[aeSdk.addresses().find(acc => acc !== current)] + const onAccountIndex = aeSdk.addresses().find(acc => acc !== current) + if (onAccountIndex == null) throw new UnexpectedTsError() + const onAccount = aeSdk.accounts[onAccountIndex] const aensName = await aeSdk.aensQuery(name) const revoke = await aensName.revoke({ onAccount }) @@ -162,6 +171,7 @@ describe('Aens', function () { const preclaim = await aeSdk.aensPreclaim(name, { onAccount }) preclaim.should.be.an('object') + if (preclaim.tx?.accountId == null) throw new UnexpectedTsError() preclaim.tx.accountId.should.be.equal(onAccount) }) @@ -178,12 +188,14 @@ describe('Aens', function () { claim.should.be.an('object') const bidFee = computeBidFee(name) - const bid = await aeSdk.aensBid(name, bidFee, { onAccount }) + const bid: Awaited> = + await aeSdk.aensBid(name, bidFee, { onAccount }) bid.should.be.an('object') const isAuctionFinished = await aeSdk.getName(name).catch(() => false) isAuctionFinished.should.be.equal(false) + if (bid.blockHeight == null) throw new UnexpectedTsError() const auctionEndBlock = computeAuctionEndBlock(name, bid.blockHeight) console.log(`BID STARTED AT ${bid.blockHeight} WILL END AT ${auctionEndBlock}`) }) diff --git a/test/integration/chain.js b/test/integration/chain.ts similarity index 76% rename from test/integration/chain.js rename to test/integration/chain.ts index db633ffdaa..cbfd38774d 100644 --- a/test/integration/chain.js +++ b/test/integration/chain.ts @@ -18,12 +18,13 @@ import { describe, it, before } from 'mocha' import { expect } from 'chai' import { spy } from 'sinon' import http from 'http' -import { getSdk } from './' +import { getSdk } from '.' import { generateKeyPair } from '../../src/utils/crypto' -import { TX_TYPE } from '../../src' +import { AeSdk, TX_TYPE, UnexpectedTsError } from '../../src' +import { EncodedData } from '../../src/utils/encoder' describe('Node Chain', function () { - let aeSdk, aeSdkWithoutAccount + let aeSdk: AeSdk, aeSdkWithoutAccount: AeSdk const { publicKey } = generateKeyPair() before(async function () { @@ -36,11 +37,13 @@ describe('Node Chain', function () { }) it('combines height queries', async () => { - spy(http, 'request') - const heights = await Promise.all(new Array(5).fill().map(() => aeSdk.height())) + const httpSpy = spy(http, 'request') + const heights = await Promise.all( + new Array(5).fill(undefined).map(async () => await aeSdk.height()) + ) expect(heights).to.eql(heights.map(() => heights[0])) - expect(http.request.callCount).to.be.equal(2) - http.request.restore() + expect(httpSpy.callCount).to.be.equal(2) + httpSpy.restore() }) it('waits for specified heights', async () => { @@ -61,22 +64,18 @@ describe('Node Chain', function () { it('Get key block', async () => { const { keyBlock } = await aeSdkWithoutAccount.getCurrentGeneration() - const keyBlockByHash = await aeSdkWithoutAccount.getKeyBlock(keyBlock.hash) + const keyBlockByHash = await aeSdkWithoutAccount.getKeyBlock(keyBlock.hash as EncodedData<'kh'>) const keyBlockByHeight = await aeSdkWithoutAccount.getKeyBlock(keyBlock.height) - const keyBlockError = await aeSdkWithoutAccount.getKeyBlock(false).catch(() => true) keyBlockByHash.should.be.an('object') keyBlockByHeight.should.be.an('object') - keyBlockError.should.be.equal(true) }) it('Get generation', async () => { const { keyBlock } = await aeSdkWithoutAccount.getCurrentGeneration() - const genByHash = await aeSdkWithoutAccount.getGeneration(keyBlock.hash) + const genByHash = await aeSdkWithoutAccount.getGeneration(keyBlock.hash as EncodedData<'kh'>) const genByHeight = await aeSdkWithoutAccount.getGeneration(keyBlock.height) - const genArgsError = await aeSdkWithoutAccount.getGeneration(true).catch(() => true) genByHash.should.be.an('object') genByHeight.should.be.an('object') - genArgsError.should.be.equal(true) }) it('polls for transactions', async () => { @@ -97,47 +96,49 @@ describe('Node Chain', function () { it('Wait for transaction confirmation', async () => { const txData = await aeSdk.spend(1000, await aeSdk.address(), { confirm: true }) + if (txData.blockHeight == null) throw new UnexpectedTsError() const isConfirmed = (await aeSdk.height()) >= txData.blockHeight + 3 isConfirmed.should.be.equal(true) const txData2 = await aeSdk.spend(1000, await aeSdk.address(), { confirm: 4 }) + if (txData2.blockHeight == null) throw new UnexpectedTsError() const isConfirmed2 = (await aeSdk.height()) >= txData2.blockHeight + 4 isConfirmed2.should.be.equal(true) }) - const accounts = new Array(10).fill().map(() => generateKeyPair()) - const transactions = [] + const accounts = new Array(10).fill(undefined).map(() => generateKeyPair()) + const transactions: Array> = [] it('multiple spends from one account', async () => { const { nextNonce } = await aeSdk.api.getAccountNextNonce(await aeSdk.address()) - spy(http, 'request') - const spends = await Promise.all(accounts.map((account, idx) => aeSdk.spend( + const httpSpy = spy(http, 'request') + const spends = await Promise.all(accounts.map(async (account, idx) => await aeSdk.spend( Math.floor(Math.random() * 1000 + 1e16), account.publicKey, { nonce: nextNonce + idx, verify: false, waitMined: false } ))) transactions.push(...spends.map(({ hash }) => hash)) const txPostCount = accounts.length - expect(http.request.args.length).to.be.equal(2 + txPostCount) - http.request.restore() + expect(httpSpy.args.length).to.be.equal(2 + txPostCount) + httpSpy.restore() }) it('multiple spends from different accounts', async () => { const receiver = await aeSdk.address() - spy(http, 'request') - const spends = await Promise.all(accounts.map(onAccount => - aeSdkWithoutAccount.spend(1e15, receiver, { + const httpSpy = spy(http, 'request') + const spends = await Promise.all(accounts.map(async onAccount => + await aeSdkWithoutAccount.spend(1e15, receiver, { nonce: 1, verify: false, onAccount, waitMined: false }))) transactions.push(...spends.map(({ hash }) => hash)) const accountGetCount = accounts.length const txPostCount = accounts.length - expect(http.request.args.length).to.be.equal(1 + accountGetCount + txPostCount) - http.request.restore() + expect(httpSpy.args.length).to.be.equal(1 + accountGetCount + txPostCount) + httpSpy.restore() }) - it('ensure transactions mined', () => Promise.all(transactions.map(hash => aeSdkWithoutAccount.poll(hash)))) + it('ensure transactions mined', async () => await Promise.all(transactions.map(async hash => await aeSdkWithoutAccount.poll(hash)))) it('multiple contract dry-runs calls at one request', async () => { const contract = await aeSdk.getContractInstance({ @@ -148,14 +149,14 @@ describe('Node Chain', function () { await contract.deploy() const { result: { gasUsed: gasLimit } } = await contract.methods.foo(5) const { nextNonce } = await aeSdk.api.getAccountNextNonce(await aeSdk.address()) - spy(http, 'request') - const numbers = new Array(32).fill().map((v, idx) => idx * 2) + const httpSpy = spy(http, 'request') + const numbers = new Array(32).fill(undefined).map((v, idx) => idx * 2) const results = (await Promise.all( numbers.map((v, idx) => contract.methods .foo(v, { nonce: nextNonce + idx, gasLimit, combine: true })) )).map(r => r.decodedResult) expect(results).to.be.eql(numbers.map(v => BigInt(v * 100))) - expect(http.request.args.length).to.be.equal(2) - http.request.restore() + expect(httpSpy.args.length).to.be.equal(2) + httpSpy.restore() }) }) diff --git a/test/integration/channel.ts b/test/integration/channel.ts index 0c323a1b9f..2b2e179427 100644 --- a/test/integration/channel.ts +++ b/test/integration/channel.ts @@ -1058,7 +1058,7 @@ describe('Channel', function () { it('can clean contract calls', async () => { await initiatorCh.cleanContractCalls() - void initiatorCh.getContractCall({ + await initiatorCh.getContractCall({ caller: await aeSdkInitiatior.address(), contract: contractAddress, round: callerNonce @@ -1142,7 +1142,7 @@ describe('Channel', function () { // } // ch.on('stateChanged', checkRound) // }) - void ch.state().should.eventually.be.fulfilled + await ch.state().should.eventually.be.fulfilled await pause(10 * 1000) }) diff --git a/test/integration/contract-aci.js b/test/integration/contract-aci.ts similarity index 91% rename from test/integration/contract-aci.js rename to test/integration/contract-aci.ts index c2bae696ae..e5e2060b54 100644 --- a/test/integration/contract-aci.js +++ b/test/integration/contract-aci.ts @@ -1,6 +1,6 @@ /* * ISC License (ISC) - * Copyright (c) 2018 aeternity developers + * Copyright (c) 2022 aeternity developers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,9 +26,14 @@ import { MissingContractDefError, NotPayableFunctionError, MissingEventDefinitionError, - AmbiguousEventDefinitionError + AmbiguousEventDefinitionError, + UnexpectedTsError } from '../../src/utils/errors' -import { getSdk } from './' +import { getSdk } from '.' +import { EncodedData } from '../../src/utils/encoder' +import { ContractInstance } from '../../src/contract/aci' +import { AeSdk } from '../../src' +import { Aci } from '../../src/apis/compiler' const identityContractSource = ` contract Identity = @@ -137,16 +142,17 @@ const fileSystem = { const notExistingContractAddress = 'ct_ptREMvyDbSh1d38t4WgYgac5oLsa2v9xwYFnG7eUWR8Er5cmT' describe('Contract instance', function () { - let aeSdk - let testContract - let testContractAddress - let testContractAci - let testContractBytecode + let aeSdk: AeSdk + let testContract: ContractInstance + let testContractAddress: EncodedData<'ct'> + let testContractAci: Aci + let testContractBytecode: EncodedData<'cb'> before(async function () { aeSdk = await getSdk() testContractAci = await aeSdk.compilerApi .generateACI({ code: testContractSource, options: { fileSystem } }) + // @ts-expect-error should be changed on api testContractBytecode = (await aeSdk.compilerApi.compileContract({ code: testContractSource, options: { fileSystem } })).bytecode @@ -175,7 +181,7 @@ describe('Contract instance', function () { it('compiles', async () => { await testContract.compile() - expect(testContract.bytecode).to.satisfy(b => b.startsWith('cb_')) + expect(testContract.bytecode).to.satisfy((b: string) => b.startsWith('cb_')) }) it('fails on calling without deployment', () => expect(testContract.methods.intFn(2)) @@ -191,13 +197,13 @@ describe('Contract instance', function () { gasPrice: '1e9', strategy: 'max' }) - expect(deployInfo.address).to.satisfy(b => b.startsWith('ct_')) + expect(deployInfo.address).to.satisfy((b: string) => b.startsWith('ct_')) expect(deployInfo.txData.tx.gas).to.be.equal(16000) expect(deployInfo.txData.tx.amount).to.be.equal(42n) expect(deployInfo.txData.gasUsed).to.be.equal(209) expect(deployInfo.txData.gasPrice).to.be.equal(1000000000n) expect(deployInfo.txData.tx.deposit).to.be.equal(0n) - expect(testContract.bytecode).to.satisfy(b => b.startsWith('cb_')) + expect(testContract.bytecode).to.satisfy((b: string) => b.startsWith('cb_')) testContractAddress = deployInfo.address }) @@ -205,8 +211,8 @@ describe('Contract instance', function () { expect((await testContract.methods.intFn(2)).decodedResult).to.be.equal(2n) }) - it('generates by aci', () => - aeSdk.getContractInstance({ aci: testContractAci, contractAddress: testContractAddress })) + it('generates by aci', async () => + await aeSdk.getContractInstance({ aci: testContractAci, contractAddress: testContractAddress })) it('fails on trying to generate with not existing contract address', () => expect(aeSdk.getContractInstance( @@ -222,8 +228,8 @@ describe('Contract instance', function () { expect(aeSdk.getContractInstance({ aci: testContractAci })) .to.be.rejectedWith(MissingContractAddressError, 'Can\'t create instance by ACI without address')) - it('generates by bytecode and aci', () => - aeSdk.getContractInstance({ bytecode: testContractBytecode, aci: testContractAci })) + it('generates by bytecode and aci', async () => + await aeSdk.getContractInstance({ bytecode: testContractBytecode, aci: testContractAci })) it('fails on generation without arguments', () => expect(aeSdk.getContractInstance()).to.be.rejectedWith(MissingContractDefError, 'Either ACI or source code is required')) @@ -243,7 +249,7 @@ describe('Contract instance', function () { expect((await contract.methods.intFn(3)).decodedResult).to.be.equal(3n) }) - it('accepts matching source code with enabled validation', () => aeSdk.getContractInstance({ + it('accepts matching source code with enabled validation', async () => await aeSdk.getContractInstance({ source: testContractSource, fileSystem, contractAddress: testContractAddress, @@ -256,14 +262,14 @@ describe('Contract instance', function () { validateBytecode: true })).to.be.rejectedWith(BytecodeMismatchError, 'Contract source do not correspond to the bytecode deployed on the chain')) - it('accepts matching bytecode with enabled validation', () => aeSdk.getContractInstance({ + it('accepts matching bytecode with enabled validation', async () => await aeSdk.getContractInstance({ bytecode: testContractBytecode, aci: testContractAci, contractAddress: testContractAddress, validateBytecode: true })) - it('rejects not matching bytecode with enabled validation', async () => expect(aeSdk.getContractInstance({ + it('rejects not matching bytecode with enabled validation', async () => await expect(aeSdk.getContractInstance({ bytecode: (await aeSdk.compilerApi.compileContract({ code: identityContractSource, options: {} })).bytecode, @@ -304,6 +310,7 @@ describe('Contract instance', function () { }) it('pays to payable function', async () => { + if (testContract.deployInfo.address == null) throw new UnexpectedTsError('testContract.deployInfo.address is null') const contractBalance = await aeSdk.getBalance(testContract.deployInfo.address) await testContract.methods.stringFn.send('test', { amount: 100 }) const balanceAfter = await aeSdk.getBalance(testContract.deployInfo.address) @@ -317,7 +324,7 @@ describe('Contract instance', function () { }) describe('Gas', () => { - let contract + let contract: ContractInstance before(async () => { contract = await aeSdk.getContractInstance({ source: testContractSource, fileSystem }) @@ -361,8 +368,8 @@ describe('Contract instance', function () { }) describe('Events parsing', () => { - let remoteContract - let eventResult + let remoteContract: ContractInstance + let eventResult: Awaited> before(async () => { remoteContract = await aeSdk.getContractInstance({ source: remoteContractSource }) @@ -409,7 +416,8 @@ describe('Contract instance', function () { }) it('decodes events using decodeEvents', () => { - expect(testContract.decodeEvents(eventResult.result.log)).to.be.eql(eventResult.decodedEvents) + expect(testContract.decodeEvents(eventResult.result.log, {})) + .to.be.eql(eventResult.decodedEvents) }) it('throws error if can\'t find event definition', () => { @@ -418,7 +426,7 @@ describe('Contract instance', function () { expect(() => testContract.decodeEvents([event])).to.throw( MissingEventDefinitionError, 'Can\'t find definition of 7165442193418278913262533136158148486147352807284929017531784742205476270109' + - ` event emitted by ${testContract.deployInfo.address}` + + ` event emitted by ${testContract.deployInfo.address as string}` + ' (use omitUnknown option to ignore events like this)' ) }) @@ -429,8 +437,12 @@ describe('Contract instance', function () { expect(testContract.decodeEvents([event], { omitUnknown: true })).to.be.eql([]) }) - const getDuplicateLog = () => [{ - address: remoteContract.deployInfo.address, + const getDuplicateLog = (): Array<{ + address: EncodedData<'ct'> + data: EncodedData<'cb'> + topics: Array + }> => [{ + address: remoteContract.deployInfo.address as EncodedData<'ct'>, data: 'cb_Xfbg4g==', topics: [ '28631352549432199952459007654025571262660118571086898449909844428770770966435', @@ -442,7 +454,7 @@ describe('Contract instance', function () { expect(() => testContract.decodeEvents(getDuplicateLog())).to.throw( AmbiguousEventDefinitionError, 'Found multiple definitions of "Duplicate" event emitted by' + - ` ${remoteContract.deployInfo.address} in "StateContract", "RemoteI" contracts` + + ` ${remoteContract.deployInfo.address ?? ''} in "StateContract", "RemoteI" contracts` + ' (use contractAddressToName option to specify contract name corresponding to address)' ) }) @@ -451,7 +463,7 @@ describe('Contract instance', function () { expect( testContract.decodeEvents( getDuplicateLog(), - { contractAddressToName: { [remoteContract.deployInfo.address]: 'RemoteI' } } + { contractAddressToName: { [remoteContract.deployInfo.address ?? '']: 'RemoteI' } } ) ).to.be.eql([{ name: 'Duplicate', @@ -487,14 +499,15 @@ describe('Contract instance', function () { expect(decodedResult).to.be.equal(1n) }) - const unsafeInt = BigInt(Number.MAX_SAFE_INTEGER + '0') + const unsafeInt = BigInt(Number.MAX_SAFE_INTEGER.toString() + '0') it('Supports unsafe integer', async () => { const { decodedResult } = await testContract.methods.intFn.get(unsafeInt) expect(decodedResult).to.be.equal(unsafeInt) }) it('Supports BigNumber', async () => { - const { decodedResult } = await testContract.methods.intFn.get(new BigNumber(unsafeInt)) + const { decodedResult } = await testContract.methods.intFn + .get(new BigNumber(unsafeInt.toString())) expect(decodedResult).to.be.equal(unsafeInt) }) }) @@ -624,14 +637,13 @@ describe('Contract instance', function () { }) it('Cast from string to int', async () => { - const mapArg = new Map([[address, ['someStringV', '324']]]) + const mapArg = new Map([[address, ['someStringV', '324']]] as const) const result = await testContract.methods.mapFn(mapArg) - mapArg.set(address, ['someStringV', 324n]) - result.decodedResult.should.be.eql(mapArg) + result.decodedResult.should.be.eql(new Map([[address, ['someStringV', 324n]]] as const)) }) it('Cast from array to map', async () => { - const mapArg = [[address, ['someStringV', 324n]]] + const mapArg = [[address, ['someStringV', 324n]]] as const const { decodedResult } = await testContract.methods.mapFn(mapArg) decodedResult.should.be.eql(new Map(mapArg)) }) @@ -725,14 +737,14 @@ describe('Contract instance', function () { it('Invalid length', async () => { const address = await aeSdk.address() - const decoded = Buffer.from(decode(address, 'ak').slice(1)) + const decoded = Buffer.from(decode(address).slice(1)) await expect(testContract.methods.hashFn(decoded)) .to.be.rejectedWith('Invalid length: got 31 bytes instead of 32 bytes') }) it('Valid', async () => { const address = await aeSdk.address() - const decoded = decode(address, 'ak') + const decoded = decode(address) const hashAsBuffer = await testContract.methods.hashFn(decoded) const hashAsHex = await testContract.methods.hashFn(decoded.toString('hex')) hashAsBuffer.decodedResult.should.be.eql(decoded) @@ -748,14 +760,14 @@ describe('Contract instance', function () { it('Invalid length', async () => { const address = await aeSdk.address() - const decoded = decode(address, 'ak') + const decoded = decode(address) await expect(testContract.methods.signatureFn(decoded)) .to.be.rejectedWith('Invalid length: got 32 bytes instead of 64 bytes') }) it('Valid', async () => { const address = await aeSdk.address() - const decoded = decode(address, 'ak') + const decoded = decode(address) const fakeSignature = Buffer.from(await aeSdk.sign(decoded)) const hashAsBuffer = await testContract.methods.signatureFn(fakeSignature) const hashAsHex = await testContract.methods.signatureFn(fakeSignature.toString('hex')) @@ -772,14 +784,14 @@ describe('Contract instance', function () { it('Invalid length', async () => { const address = await aeSdk.address() - const decoded = decode(address, 'ak') + const decoded = decode(address) await expect(testContract.methods.bytesFn(Buffer.from([...decoded, 2]))) .to.be.rejectedWith('is not of type [{bytes,32}]') }) it('Valid', async () => { const address = await aeSdk.address() - const decoded = decode(address, 'ak') + const decoded = decode(address) const hashAsBuffer = await testContract.methods.bytesFn(decoded) const hashAsHex = await testContract.methods.bytesFn(decoded.toString('hex')) hashAsBuffer.decodedResult.should.be.eql(decoded) diff --git a/test/integration/contract.js b/test/integration/contract.ts similarity index 91% rename from test/integration/contract.js rename to test/integration/contract.ts index 5daf1a085a..9100519e46 100644 --- a/test/integration/contract.js +++ b/test/integration/contract.ts @@ -1,6 +1,6 @@ /* * ISC License (ISC) - * Copyright (c) 2018 aeternity developers + * Copyright (c) 2022 aeternity developers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,11 +17,13 @@ import { expect } from 'chai' import { before, describe, it } from 'mocha' import { randomName } from '../utils' -import { BaseAe, getSdk, publicKey, compilerUrl } from './' +import { BaseAe, getSdk, publicKey, compilerUrl } from '.' import { IllegalArgumentError, NodeInvocationError, MemoryAccount, generateKeyPair, - commitmentHash, decode, encode, DRY_RUN_ACCOUNT, messageToHash, salt + commitmentHash, decode, encode, DRY_RUN_ACCOUNT, messageToHash, salt, UnexpectedTsError, AeSdk } from '../../src' +import { EncodedData } from '../../src/utils/encoder' +import { ContractInstance } from '../../src/contract/aci' const identityContract = ` contract Identity = @@ -114,10 +116,10 @@ contract Sign = ` describe('Contract', function () { - let aeSdk - let bytecode - let contract - let deployed + let aeSdk: AeSdk + let bytecode: EncodedData<'cb'> + let contract: ContractInstance + let deployed: ContractInstance['deployInfo'] before(async function () { aeSdk = await getSdk() @@ -130,8 +132,8 @@ describe('Contract', function () { it('compiles Sophia code', async () => { bytecode = (await aeSdk.compilerApi.compileContract({ code: identityContract, options: {} - })).bytecode - expect(bytecode).to.satisfy(b => b.startsWith('cb_')) + })).bytecode as EncodedData<'cb'> + expect(bytecode).to.satisfy((b: string) => b.startsWith('cb_')) }) it('deploys precompiled bytecode', async () => { @@ -170,6 +172,7 @@ describe('Contract', function () { contract.options.onAccount = onAccount deployed = await contract.deploy() const address = await onAccount.address() + if (deployed?.result?.callerId == null) throw new UnexpectedTsError() expect(deployed.result.callerId).to.be.equal(address) expect((await contract.methods.getArg(42, { callStatic: true })).result.callerId) .to.be.equal(address) @@ -243,17 +246,17 @@ describe('Contract', function () { }) describe('Namespaces', () => { - let contract + let contract: ContractInstance it('Can compiler contract with external deps', async () => { contract = await aeSdk.getContractInstance({ source: contractWithLib, fileSystem: { testLib: libContract } }) - expect(await contract.compile()).to.satisfy(b => b.startsWith('cb_')) + expect(await contract.compile()).to.satisfy((b: string) => b.startsWith('cb_')) }) it('Throw error when try to compile contract without providing external deps', async () => { - await expect(aeSdk.getContractInstance({ source: contractWithLib, options: {} })) + await expect(aeSdk.getContractInstance({ source: contractWithLib })) .to.be.rejectedWith('Couldn\'t find include file') }) @@ -275,13 +278,12 @@ describe('Contract', function () { }) describe('Sophia Compiler', function () { - let bytecode + let bytecode: string it('compile', async () => { bytecode = (await aeSdk.compilerApi.compileContract({ code: identityContract, options: {} })).bytecode - expect(bytecode).to.be.a('string') expect(bytecode.split('_')[0]).to.be.equal('cb') }) @@ -311,7 +313,7 @@ describe('Contract', function () { }) it('throws clear exception if generating ACI with no arguments', async () => { - await expect(aeSdk.compilerApi.generateACI({ options: {} })) + await expect(aeSdk.compilerApi.generateACI({ options: {} } as any)) .to.be.rejectedWith('Error "body.code cannot be null or undefined." occurred in serializing the payload - undefined') }) @@ -323,24 +325,25 @@ describe('Contract', function () { it('Use invalid compiler url', async () => { aeSdk.setCompilerUrl('https://compiler.aepps.comas') - await expect(aeSdk.compilerApi.generateACI({ code: 'test' })) + await expect(aeSdk.compilerApi.generateACI({ code: 'test', options: {} })) .to.be.rejectedWith('getaddrinfo ENOTFOUND compiler.aepps.comas') aeSdk.setCompilerUrl(compilerUrl) }) }) describe('AENS operation delegation', () => { - let contract - let contractId + let contract: ContractInstance + let contractId: EncodedData<'ct'> const name = randomName(15) const nameSalt = salt() - let owner - let newOwner - let delegationSignature + let owner: EncodedData<'ak'> + let newOwner: EncodedData<'ak'> + let delegationSignature: string before(async () => { contract = await aeSdk.getContractInstance({ source: aensDelegationContract }) await contract.deploy() + if (contract.deployInfo.address == null) throw new UnexpectedTsError() contractId = contract.deployInfo.address; [owner, newOwner] = aeSdk.addresses() }) @@ -348,7 +351,7 @@ describe('Contract', function () { it('preclaims', async () => { const commitmentId = commitmentHash(name, nameSalt) // TODO: provide more convenient way to create the decoded commitmentId ? - const commitmentIdDecoded = decode(commitmentId, 'cm') + const commitmentIdDecoded = decode(commitmentId) const preclaimSig = await aeSdk.createAensDelegationSignature(contractId) const preclaim = await contract.methods .signedPreclaim(owner, commitmentIdDecoded, preclaimSig) @@ -404,19 +407,20 @@ describe('Contract', function () { }) describe('Oracle operation delegation', () => { - let contract - let contractId - let address - let oracle - let oracleId - let queryObject - let delegationSignature + let contract: ContractInstance + let contractId: EncodedData<'ct'> + let address: EncodedData<'ak'> + let oracle: Awaited> + let oracleId: EncodedData<'ok'> + let queryObject: Awaited> + let delegationSignature: string const queryFee = 500000 const ttl = { RelativeTTL: [50] } before(async () => { contract = await aeSdk.getContractInstance({ source: oracleContract }) await contract.deploy() + if (contract.deployInfo.address == null) throw new UnexpectedTsError() contractId = contract.deployInfo.address address = await aeSdk.address() oracleId = encode(decode(address), 'ok') @@ -463,7 +467,8 @@ describe('Contract', function () { oracle.id, queryObject.id, respondSig, r ) response.result.returnType.should.be.equal('ok') - const queryObject2 = await aeSdk.getQueryObject(oracle.id, queryObject.id) + // TODO type should be corrected in node api + const queryObject2 = await aeSdk.getQueryObject(oracle.id, queryObject.id as EncodedData<'oq'>) queryObject2.decodedResponse.should.be.equal(r) }) }) diff --git a/test/integration/ga.js b/test/integration/ga.ts similarity index 87% rename from test/integration/ga.js rename to test/integration/ga.ts index 8578c97810..3a8c1fd535 100644 --- a/test/integration/ga.js +++ b/test/integration/ga.ts @@ -1,6 +1,6 @@ /* * ISC License (ISC) - * Copyright (c) 2018 aeternity developers + * Copyright (c) 2022 aeternity developers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,11 +17,13 @@ import { describe, it, before } from 'mocha' import { expect } from 'chai' -import { getSdk } from './' +import { getSdk } from '.' import { generateKeyPair } from '../../src/utils/crypto' import { encode } from '../../src/utils/encoder' import MemoryAccount from '../../src/account/memory' import { unpackTx } from '../../src/tx/builder' +import { ContractInstance } from '../../src/contract/aci' +import { AeSdk, TX_TYPE, UnexpectedTsError } from '../../src' const authContractSource = `contract BlindAuth = record state = { txHash: option(hash) } @@ -37,13 +39,14 @@ const authContractSource = `contract BlindAuth = Some(tx_hash) => true ` describe('Generalized Account', function () { - let aeSdk + let aeSdk: AeSdk const gaAccount = generateKeyPair() - let authContract + let authContract: ContractInstance before(async function () { aeSdk = await getSdk() await aeSdk.spend('100000000000000000000', gaAccount.publicKey) + if (aeSdk.selectedAddress == null) throw new UnexpectedTsError() aeSdk.removeAccount(aeSdk.selectedAddress) await aeSdk.addAccount(new MemoryAccount({ keypair: gaAccount }), { select: true }) }) @@ -62,7 +65,7 @@ describe('Generalized Account', function () { .should.be.rejectedWith(`Account ${gaAccount.publicKey} is already GA`) }) - const r = () => Math.floor(Math.random() * 20).toString() + const r = (): string => Math.floor(Math.random() * 20).toString() const { publicKey } = generateKeyPair() it('Init MemoryAccount for GA and Spend using GA', async () => { @@ -80,7 +83,7 @@ describe('Generalized Account', function () { const { rawTx } = await aeSdk.spend( 10000, publicKey, { authData: { source: authContractSource, args: [r()] } } ) - const spendTx = encode(unpackTx(rawTx).tx.encodedTx.tx.tx.tx.encodedTx.rlpEncoded, 'tx') + const spendTx = encode(unpackTx(rawTx, TX_TYPE.signed).tx.encodedTx.tx.tx.tx.encodedTx.rlpEncoded, 'tx') expect(await aeSdk.buildAuthTxHash(spendTx)).to.be .eql((await authContract.methods.getTxHash()).decodedResult) }) diff --git a/test/integration/oracle.js b/test/integration/oracle.ts similarity index 75% rename from test/integration/oracle.js rename to test/integration/oracle.ts index d1875feffd..e42d05fc5d 100644 --- a/test/integration/oracle.js +++ b/test/integration/oracle.ts @@ -17,29 +17,32 @@ import { describe, it, before } from 'mocha' import { expect } from 'chai' -import { getSdk } from './' +import { getSdk } from '.' import { generateKeyPair } from '../../src/utils/crypto' import MemoryAccount from '../../src/account/memory' -import { QUERY_FEE } from '../../src/tx/builder/schema' +import { ORACLE_TTL_TYPES, QUERY_FEE } from '../../src/tx/builder/schema' import { decode } from '../../src/tx/builder/helpers' +import { postQueryToOracle, registerOracle } from '../../src/ae/oracle' +import { EncodedData } from '../../src/utils/encoder' +import { AeSdk, UnexpectedTsError } from '../../src' describe('Oracle', function () { - let aeSdk - let oracle - let query + let aeSdk: AeSdk + let oracle: Awaited> + let query: Awaited> const queryResponse = "{'tmp': 30}" const account = generateKeyPair() before(async function () { aeSdk = await getSdk() await aeSdk.spend(1e20, account.publicKey) - aeSdk.addAccount(new MemoryAccount({ keypair: account }), { select: true }) + await aeSdk.addAccount(new MemoryAccount({ keypair: account }), { select: true }) }) it('Register Oracle with 5000 TTL', async () => { const expectedOracleId = `ok_${(await aeSdk.address()).slice(3)}` oracle = await aeSdk.registerOracle( - "{'city': str}", "{'tmp': num}", { oracleTtl: { type: 'delta', value: 5000 } } + "{'city': str}", "{'tmp': num}", { oracleTtlType: ORACLE_TTL_TYPES.delta, oracleTtlValue: 5000 } ) oracle.id.should.be.equal(expectedOracleId) }) @@ -77,7 +80,7 @@ describe('Oracle', function () { query = await oracle.getQuery(query.id) expect(query.decodedResponse).to.be.equal(queryResponse) - expect(decode(query.response, 'or').toString()).to.be.equal(queryResponse) + expect(decode(query.response as EncodedData<'or'>).toString()).to.be.equal(queryResponse) }) it('Poll for response', async () => { @@ -85,29 +88,32 @@ describe('Oracle', function () { response.should.be.equal(queryResponse) }) - describe('Oracle query fee settings', async () => { - let oracleWithFee + describe('Oracle query fee settings', () => { + let oracleWithFee: Awaited> const queryFee = 24000n const account = generateKeyPair() before(async function () { await aeSdk.spend(1e15, account.publicKey) - aeSdk.addAccount(new MemoryAccount({ keypair: account }), { select: true }) - oracleWithFee = await aeSdk.registerOracle("{'city': str}", "{'tmp': num}", { queryFee, onAccount: account }) + await aeSdk.addAccount(new MemoryAccount({ keypair: account }), { select: true }) + oracleWithFee = await aeSdk.registerOracle("{'city': str}", "{'tmp': num}", { queryFee: queryFee.toString(), onAccount: account }) }) it('Post Oracle Query with default query fee', async () => { query = await oracle.postQuery("{'city': 'Berlin'}") + if (query.tx?.queryFee == null) throw new UnexpectedTsError() query.tx.queryFee.should.be.equal(BigInt(QUERY_FEE)) }) it('Post Oracle Query with registered query fee', async () => { query = await oracleWithFee.postQuery("{'city': 'Berlin'}") + if (query.tx?.queryFee == null) throw new UnexpectedTsError() query.tx.queryFee.should.be.equal(queryFee) }) it('Post Oracle Query with custom query fee', async () => { query = await oracleWithFee.postQuery("{'city': 'Berlin'}", { queryFee: queryFee + 2000n }) + if (query.tx?.queryFee == null) throw new UnexpectedTsError() query.tx.queryFee.should.be.equal(queryFee + 2000n) }) }) diff --git a/test/integration/paying-for.js b/test/integration/paying-for.ts similarity index 82% rename from test/integration/paying-for.js rename to test/integration/paying-for.ts index c77bb6c8e9..1316e033b2 100644 --- a/test/integration/paying-for.js +++ b/test/integration/paying-for.ts @@ -1,6 +1,6 @@ /* * ISC License (ISC) - * Copyright (c) 2021 aeternity developers + * Copyright (c) 2022 aeternity developers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,10 +19,12 @@ import { describe, it, before } from 'mocha' import { expect } from 'chai' import BigNumber from 'bignumber.js' import { getSdk, BaseAe } from './' -import { generateKeyPair, MemoryAccount, TX_TYPE } from '../../src' +import { AeSdk, generateKeyPair, MemoryAccount, TX_TYPE, UnexpectedTsError } from '../../src' +import { ContractInstance } from '../../src/contract/aci' +import { EncodedData } from '../../src/utils/encoder' describe('Paying for transaction of another account', function () { - let aeSdk + let aeSdk: AeSdk before(async function () { aeSdk = await getSdk() @@ -39,11 +41,14 @@ describe('Paying for transaction of another account', function () { }) const signedSpendTx = await aeSdk.signTransaction(spendTx, { onAccount: sender, innerTx: true }) const payerBalanceBefore = await aeSdk.getBalance(await aeSdk.address()) - const { - fee: outerFee, tx: { tx: { fee: innerFee } } - } = (await aeSdk.payForTransaction(signedSpendTx)).tx + + const tx = (await aeSdk.payForTransaction(signedSpendTx)).tx + const outerFee = tx?.fee + const innerFee = tx?.tx?.tx.fee + if (outerFee == null || innerFee == null) throw new UnexpectedTsError() expect(await aeSdk.getBalance(await aeSdk.address())).to.equal( - new BigNumber(payerBalanceBefore).minus(outerFee).minus(innerFee).toFixed() + new BigNumber(payerBalanceBefore) + .minus(outerFee.toString()).minus(innerFee.toString()).toFixed() ) expect(await aeSdk.getBalance(await sender.address())).to.equal('0') expect(await aeSdk.getBalance(await receiver.address())).to.equal('10000') @@ -55,9 +60,9 @@ describe('Paying for transaction of another account', function () { entrypoint init(x: int): state = { value = x } entrypoint getValue(): int = state.value stateful entrypoint setValue(x: int) = put(state{ value = x })` - let contractAddress - let aeSdkNotPayingFee - let payingContract + let contractAddress: EncodedData<'ct'> + let aeSdkNotPayingFee: any + let payingContract: ContractInstance it('pays for contract deployment', async () => { aeSdkNotPayingFee = await BaseAe({ diff --git a/test/integration/txVerification.ts b/test/integration/txVerification.ts index 083de0c4d3..29729da5c0 100644 --- a/test/integration/txVerification.ts +++ b/test/integration/txVerification.ts @@ -4,12 +4,13 @@ import { getSdk } from '.' import { generateKeyPair } from '../../src/utils/crypto' import MemoryAccount from '../../src/account/memory' import verifyTransaction from '../../src/tx/validator' -import { InvalidTxParamsError } from '../../src/utils/errors' +import { InvalidTxError, InvalidTxParamsError } from '../../src/utils/errors' import { TX_TYPE } from '../../src/tx/builder/schema' +import { AeSdk } from '../../src' describe('Verify Transaction', function () { - let aeSdk: any - let node: any + let aeSdk: AeSdk + let node: typeof aeSdk.api before(async () => { aeSdk = await getSdk() @@ -18,7 +19,7 @@ describe('Verify Transaction', function () { }) it('validates params in buildRawTx', async () => { - await expect(aeSdk.buildTx(TX_TYPE.spend, {})).to.eventually.be + await expect(aeSdk.buildTx(TX_TYPE.spend, {} as any)).to.eventually.be .rejectedWith(InvalidTxParamsError, 'Transaction field senderId is missed') }) @@ -28,7 +29,7 @@ describe('Verify Transaction', function () { recipientId: await aeSdk.address(), amount: 1e30, fee: '1000', - nonce: '1', + nonce: 1, ttl: 2, absoluteTtl: true }) @@ -61,7 +62,7 @@ describe('Verify Transaction', function () { ttl: 2, absoluteTtl: true }) - const error = await aeSdk.send(spendTx).catch((e: Error) => e) + const error = await aeSdk.send(spendTx).catch((e: InvalidTxError) => e) as InvalidTxError expect(error.validation).to.have.lengthOf(1) })