UNPKG

@radixdlt/application

Version:

A JavaScript client library for interacting with the Radix Distributed Ledger.

489 lines (437 loc) 13 kB
/** * @jest-environment ./packages/application/test/_load-rpc.ts */ /*import { nodeAPI, TransactionIdentifier, RawExecutedAction, RawToken, Token, ActionType, ExecutedAction, ExecutedOtherAction, ExecutedTransferTokensAction, BuildTransactionEndpoint, FinalizeTransactionEndpoint, LookupTransactionEndpoint, LookupValidatorEndpoint, NativeTokenEndpoint, NetworkIdEndpoint, NetworkTransactionDemandEndpoint, NetworkTransactionThroughputEndpoint, StakePositionsEndpoint, SubmitTransactionEndpoint, TokenBalancesEndpoint, TokenInfoEndpoint, TransactionHistoryEndpoint, TransactionStatusEndpoint, UnstakePositionsEndpoint, ValidatorsEndpoint, ApiMethod, Message, } from '../src' import { Amount, Network } from '@radixdlt/primitives' import { isArray, isObject } from '@radixdlt/util' import { ContentDescriptorObject, MethodObject, OpenrpcDocument, } from '@open-rpc/meta-schema' import { AccountAddress, ResourceIdentifier, ValidatorAddress, } from '@radixdlt/account' const faker = require('json-schema-faker') let mockClientReturnValue: any function mockHTTPTransport() {} function mockRequestManager() {} function mockClient() { return { request: async () => mockClientReturnValue, } } jest.mock('@open-rpc/client-js', () => ({ Client: mockClient, HTTPTransport: mockHTTPTransport, RequestManager: mockRequestManager, })) const executedActionFromRaw = (action: RawExecutedAction): ExecutedAction => { if (action.type === ActionType.TOKEN_TRANSFER) { const executed: ExecutedTransferTokensAction = { ...action, // transactionType: TransactionType.OUTGOING, from: AccountAddress.fromUnsafe(action.from)._unsafeUnwrap({ withStackTrace: true, }), to: AccountAddress.fromUnsafe(action.to)._unsafeUnwrap({ withStackTrace: true, }), rri: ResourceIdentifier.fromUnsafe(action.rri)._unsafeUnwrap({ withStackTrace: true, }), amount: Amount.fromUnsafe(action.amount)._unsafeUnwrap({ withStackTrace: true, }), } return executed } else if ( action.type === ActionType.STAKE_TOKENS || action.type === ActionType.UNSTAKE_TOKENS ) { return { ...action, from: AccountAddress.fromUnsafe(action.from)._unsafeUnwrap({ withStackTrace: true, }), validator: ValidatorAddress.fromUnsafe( action.validator, )._unsafeUnwrap({ withStackTrace: true }), amount: Amount.fromUnsafe(action.amount)._unsafeUnwrap({ withStackTrace: true, }), } } else { const executed: ExecutedOtherAction = { type: ActionType.OTHER, } return executed } } // @ts-ignore const rpcSpec: OpenrpcDocument = global.rpcSpec const tokenInfoFromResponse = (response: RawToken): Token => ({ name: response.name, rri: ResourceIdentifier.fromUnsafe(response.rri)._unsafeUnwrap({ withStackTrace: true, }), symbol: response.symbol, description: response.description, granularity: Amount.fromUnsafe(response.granularity)._unsafeUnwrap(), isSupplyMutable: response.isSupplyMutable, currentSupply: Amount.fromUnsafe(response.currentSupply)._unsafeUnwrap(), tokenInfoURL: new URL(response.tokenInfoURL), iconURL: new URL(response.iconURL), }) const methodParams = { [rpcSpec.methods[0].name]: {}, [rpcSpec.methods[1].name]: { rri: 'xrd_tr1qyf0x76s', }, [rpcSpec.methods[2].name]: { address: 'rdx1qsps28kdn4epn0c9ej2rcmwfz5a4jdhq2ez03x7h6jefvr4fnwnrtqqjaj7dt', }, [rpcSpec.methods[3].name]: { address: 'rdx1qsps28kdn4epn0c9ej2rcmwfz5a4jdhq2ez03x7h6jefvr4fnwnrtqqjaj7dt', size: 1, cursor: 'xyz', }, [rpcSpec.methods[4].name]: { address: 'rdx1qsps28kdn4epn0c9ej2rcmwfz5a4jdhq2ez03x7h6jefvr4fnwnrtqqjaj7dt', }, [rpcSpec.methods[5].name]: { address: 'rdx1qsps28kdn4epn0c9ej2rcmwfz5a4jdhq2ez03x7h6jefvr4fnwnrtqqjaj7dt', }, [rpcSpec.methods[6].name]: { txID: 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', }, [rpcSpec.methods[7].name]: { txID: 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', }, [rpcSpec.methods[8].name]: { size: 1, cursor: 'xyz', }, [rpcSpec.methods[9].name]: { validatorAddress: 'tv1qdqft0u899axwce955fkh9rundr5s2sgvhpp8wzfe3ty0rn0rgqj2x6y86p', }, [rpcSpec.methods[10].name]: {}, [rpcSpec.methods[11].name]: {}, [rpcSpec.methods[12].name]: {}, [rpcSpec.methods[13].name]: { actions: [ { amount: '100000000000000000', from: 'brx1qsphund3df3xmycqr9fud8tyvspru95tytezy0ke2pk0gpjukjltjscyn03ah', to: 'brx1qsppypnmrwl95h70cx0zm09lgf8f047r5j9hxqgre92lf53kzq07h0gz9a4hy', rri: 'xrd_tr1qyf0x76s', type: 'TokenTransfer', }, ], feePayer: 'rdx1qsps28kdn4epn0c9ej2rcmwfz5a4jdhq2ez03x7h6jefvr4fnwnrtqqjaj7dt', message: 'xyz', }, [rpcSpec.methods[14].name]: { transaction: { blob: 'xyz', }, signatureDER: 'xyz', publicKeyOfSigner: 'xyz', }, [rpcSpec.methods[15].name]: { transaction: { blob: 'xyz', }, signatureDER: 'xyz', publicKeyOfSigner: 'xyz', txID: 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', }, } const expectedDecodedResponses = { [rpcSpec.methods[0].name]: ( response: NativeTokenEndpoint.Response, ): NativeTokenEndpoint.DecodedResponse => tokenInfoFromResponse(response), [rpcSpec.methods[1].name]: ( response: TokenInfoEndpoint.Response, ): TokenInfoEndpoint.DecodedResponse => tokenInfoFromResponse(response), [rpcSpec.methods[2].name]: ( response: TokenBalancesEndpoint.Response, ): TokenBalancesEndpoint.DecodedResponse => ({ owner: AccountAddress.fromUnsafe(response.owner)._unsafeUnwrap(), tokenBalances: [ { tokenIdentifier: ResourceIdentifier.fromUnsafe( response.tokenBalances[0].rri, )._unsafeUnwrap({ withStackTrace: true }), amount: Amount.fromUnsafe( response.tokenBalances[0].amount, )._unsafeUnwrap(), }, ], }), [rpcSpec.methods[3].name]: ( response: TransactionHistoryEndpoint.Response, ): TransactionHistoryEndpoint.DecodedResponse => { const txID = TransactionIdentifier.create( response.transactions[0].txID, )._unsafeUnwrap({ withStackTrace: true }) return { cursor: response.cursor, transactions: [ { txID, sentAt: new Date(response.transactions[0].sentAt), fee: Amount.fromUnsafe( response.transactions[0].fee, )._unsafeUnwrap({ withStackTrace: true }), message: 'Example message', actions: response.transactions[0].actions.map(raw => executedActionFromRaw(raw), ), }, ], } }, [rpcSpec.methods[4].name]: ( response: StakePositionsEndpoint.Response, ): StakePositionsEndpoint.DecodedResponse => [ { validator: ValidatorAddress.fromUnsafe( response[0].validator, )._unsafeUnwrap({ withStackTrace: true }), amount: Amount.fromUnsafe(response[0].amount)._unsafeUnwrap({ withStackTrace: true, }), }, ], [rpcSpec.methods[5].name]: ( response: UnstakePositionsEndpoint.Response, ): UnstakePositionsEndpoint.DecodedResponse => [ { amount: Amount.fromUnsafe(response[0].amount)._unsafeUnwrap({ withStackTrace: true, }), validator: ValidatorAddress.fromUnsafe( response[0].validator, )._unsafeUnwrap({ withStackTrace: true }), epochsUntil: response[0].epochsUntil, withdrawTxID: TransactionIdentifier.create( response[0].withdrawTxID, )._unsafeUnwrap({ withStackTrace: true }), }, ], [rpcSpec.methods[6].name]: ( response: LookupTransactionEndpoint.Response, ): LookupTransactionEndpoint.DecodedResponse => { const txID = TransactionIdentifier.create(response.txID)._unsafeUnwrap({ withStackTrace: true, }) return { txID, sentAt: new Date(response.sentAt), fee: Amount.fromUnsafe(response.fee)._unsafeUnwrap({ withStackTrace: true, }), message: 'Example message', actions: response.actions.map(action => executedActionFromRaw(action), ), } }, [rpcSpec.methods[7].name]: ( response: TransactionStatusEndpoint.Response, ): TransactionStatusEndpoint.DecodedResponse => ({ txID: TransactionIdentifier.create(response.txID)._unsafeUnwrap({ withStackTrace: true, }), status: response.status, }), [rpcSpec.methods[8].name]: ( response: ValidatorsEndpoint.Response, ): ValidatorsEndpoint.DecodedResponse => ({ cursor: response.cursor, validators: [ { address: ValidatorAddress.fromUnsafe( response.validators[0].address, )._unsafeUnwrap({ withStackTrace: true }), ownerAddress: AccountAddress.fromUnsafe( response.validators[0].ownerAddress, )._unsafeUnwrap({ withStackTrace: true }), name: response.validators[0].name, infoURL: new URL(response.validators[0].infoURL), totalDelegatedStake: Amount.fromUnsafe( response.validators[0].totalDelegatedStake, )._unsafeUnwrap({ withStackTrace: true }), validatorFee: response.validators[0].validatorFee, uptimePercentage: response.validators[0].uptimePercentage, proposalsCompleted: response.validators[0].proposalsCompleted, proposalsMissed: response.validators[0].proposalsMissed, registered: response.validators[0].registered, ownerDelegation: Amount.fromUnsafe( response.validators[0].ownerDelegation, )._unsafeUnwrap({ withStackTrace: true }), isExternalStakeAccepted: response.validators[0].isExternalStakeAccepted, }, ], }), [rpcSpec.methods[9].name]: ( response: LookupValidatorEndpoint.Response, ): LookupValidatorEndpoint.DecodedResponse => ({ address: ValidatorAddress.fromUnsafe(response.address)._unsafeUnwrap({ withStackTrace: true, }), ownerAddress: AccountAddress.fromUnsafe( response.ownerAddress, )._unsafeUnwrap({ withStackTrace: true, }), name: response.name, infoURL: new URL(response.infoURL), totalDelegatedStake: Amount.fromUnsafe( response.totalDelegatedStake, )._unsafeUnwrap({ withStackTrace: true }), ownerDelegation: Amount.fromUnsafe( response.ownerDelegation, )._unsafeUnwrap({ withStackTrace: true }), validatorFee: response.validatorFee, uptimePercentage: response.uptimePercentage, proposalsCompleted: response.proposalsCompleted, proposalsMissed: response.proposalsMissed, registered: response.registered, isExternalStakeAccepted: response.isExternalStakeAccepted, }), [rpcSpec.methods[10].name]: ( response: NetworkIdEndpoint.Response, ): NetworkIdEndpoint.DecodedResponse => ({ networkId: Network.MAINNET, }), [rpcSpec.methods[11].name]: ( response: NetworkTransactionThroughputEndpoint.Response, ): NetworkTransactionThroughputEndpoint.DecodedResponse => ({ tps: response.tps, }), [rpcSpec.methods[12].name]: ( response: NetworkTransactionDemandEndpoint.Response, ): NetworkTransactionDemandEndpoint.DecodedResponse => ({ tps: response.tps, }), [rpcSpec.methods[13].name]: ( response: BuildTransactionEndpoint.Response, ): BuildTransactionEndpoint.DecodedResponse => ({ transaction: { blob: response.transaction.blob, hashOfBlobToSign: response.transaction.hashOfBlobToSign, }, fee: Amount.fromUnsafe(response.fee)._unsafeUnwrap({ withStackTrace: true, }), }), [rpcSpec.methods[14].name]: ( response: FinalizeTransactionEndpoint.Response, ): FinalizeTransactionEndpoint.DecodedResponse => ({ txID: TransactionIdentifier.create(response.txID)._unsafeUnwrap({ withStackTrace: true, }), blob: '', }), [rpcSpec.methods[15].name]: ( response: SubmitTransactionEndpoint.Response, ): SubmitTransactionEndpoint.DecodedResponse => ({ txID: TransactionIdentifier.create(response.txID)._unsafeUnwrap({ withStackTrace: true, }), }), } const client = nodeAPI(new URL('http://xyz')) const testRpcMethod = (method: MethodObject, index: number) => { it(`should decode ${method.name} response`, async () => { const mockedResult = method.examples ? (method.examples[0] as any).result.value : faker.generate((method.result as ContentDescriptorObject).schema) mockClientReturnValue = mockedResult const expected = expectedDecodedResponses[method.name](mockedResult) // @ts-ignore const result = await client[method.name]( // @ts-ignore methodParams[method.name], ) if (result.isErr()) { throw result.error } const response = result.value const checkEquality = ( obj1: Record<string, any>, obj2: Record<string, any>, ) => { if (obj1.equals) { if (!obj2.equals) throw Error(`Type mismatch when checking for equality.`) expect(obj1.equals(obj2)).toEqual(true) } else { for (const key in obj1) { const value1 = obj1[key] const value2 = obj2[key] isObject(value1) ? checkEquality(value1, value2) : isArray(value1) ? value1.forEach((item, i) => checkEquality(item as any, value2[i]), ) : expect(value1).toEqual(value2) } } } checkEquality(expected, response) }) } describe.skip('json-rpc spec', () => { rpcSpec.methods .filter(method => Object.values(ApiMethod).includes(method.name as ApiMethod), ) .forEach((method, i) => testRpcMethod(method, i)) }) */