Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add /accounts/:accountId/convert endpoint #1007

Merged
merged 11 commits into from
Sep 21, 2022
1 change: 1 addition & 0 deletions src/chains-config/kusamaControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { initLRUCache } from './cache/lruCache';
export const kusamaControllers: ControllerConfig = {
controllers: [
'AccountsBalanceInfo',
'AccountsConvert',
'AccountsStakingInfo',
'AccountsStakingPayouts',
'AccountsValidate',
Expand Down
1 change: 1 addition & 0 deletions src/chains-config/polkadotControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { initLRUCache } from './cache/lruCache';
export const polkadotControllers: ControllerConfig = {
controllers: [
'AccountsBalanceInfo',
'AccountsConvert',
'AccountsStakingInfo',
'AccountsStakingPayouts',
'AccountsValidate',
Expand Down
1 change: 1 addition & 0 deletions src/chains-config/westendControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { initLRUCache } from './cache/lruCache';
export const westendControllers: ControllerConfig = {
controllers: [
'AccountsBalanceInfo',
'AccountsConvert',
'AccountsStakingInfo',
'AccountsStakingPayouts',
'AccountsValidate',
Expand Down
81 changes: 81 additions & 0 deletions src/controllers/accounts/AccountsConvertController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import { ApiPromise } from '@polkadot/api';
import { KeypairType } from '@polkadot/util-crypto/types';
import { RequestHandler } from 'express';
import { BadRequest } from 'http-errors';

import { AccountsConvertService } from '../../services/accounts';
import AbstractController from '../AbstractController';

export default class AccountsConvertController extends AbstractController<AccountsConvertService> {
constructor(api: ApiPromise) {
super(api, '/accounts/:address/convert', new AccountsConvertService(api));
this.initRoutes();
}

protected initRoutes(): void {
this.safeMountAsyncGetHandlers([['', this.accountConvert]]);
}

private accountConvert: RequestHandler = (
{ params: { address }, query: { scheme, prefix, publicKey } },
res
) => {
// Validation of the `scheme` query param
const cryptoScheme = (
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
typeof scheme !== 'string' ? 'sr25519' : scheme
) as KeypairType;
if (
!(
cryptoScheme === 'ed25519' ||
cryptoScheme === 'sr25519' ||
cryptoScheme === 'ecdsa'
)
Comment on lines +46 to +50
Copy link
Collaborator

@jsdw jsdw Sep 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally happy with this!

When there are lots of conditions you can also use an approach like if (!['ed25519', 'sr25519', 'ecdsa'].includes(cryptoScheme)) { ... }, but your way is more efficient :)

) {
throw new BadRequest(
'`scheme` can have one of those 3 values [ed25519, sr25519, ecdsa]'
);
}

// Validation of the `prefix` query param
const networkPrefix = typeof prefix !== 'string' ? '42' : prefix;
const ss58Prefix = this.parseNumberOrThrow(
networkPrefix,
'`prefix` provided is not a number.'
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
);

// Validation of the `publicKey` query param
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
if (
!(
String(publicKey).toLowerCase() === 'true' ||
String(publicKey).toLowerCase() === 'false' ||
publicKey === undefined
)
) {
throw new BadRequest(
'`publicKey` can be either true or false (boolean value)'
);
}
const pubKey = typeof publicKey !== 'string' ? true : publicKey === 'true';
TarikGul marked this conversation as resolved.
Show resolved Hide resolved

AccountsConvertController.sanitizedSend(
res,
this.service.accountConvert(address, cryptoScheme, ss58Prefix, pubKey)
);
};
}
1 change: 1 addition & 0 deletions src/controllers/accounts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

export { default as AccountsAssets } from './AccountsAssetsController';
export { default as AccountsBalanceInfo } from './AccountsBalanceInfoController';
export { default as AccountsConvert } from './AccountsConvertController';
export { default as AccountsStakingInfo } from './AccountsStakingInfoController';
export { default as AccountsStakingPayouts } from './AccountsStakingPayoutsController';
export { default as AccountsValidate } from './AccountsValidateController';
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import {
AccountsAssets,
AccountsBalanceInfo,
AccountsConvert,
AccountsStakingInfo,
AccountsStakingPayouts,
AccountsValidate,
Expand Down Expand Up @@ -47,6 +48,7 @@ export const controllers = {
BlocksTrace,
AccountsAssets,
AccountsBalanceInfo,
AccountsConvert,
AccountsStakingInfo,
AccountsValidate,
AccountsVestingInfo,
Expand Down
72 changes: 72 additions & 0 deletions src/services/accounts/AccountsConvertService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import { Keyring } from '@polkadot/api';
import { isHex } from '@polkadot/util';
import { allNetworks } from '@polkadot/util-crypto';
import { KeypairType } from '@polkadot/util-crypto/types';
import { BadRequest } from 'http-errors';

import { IAccountConvert } from '../../types/responses/AccountConvert';
import { AbstractService } from '../AbstractService';

export class AccountsConvertService extends AbstractService {
/**
* Takes a given accountId and converts it to a SS58 address
* based on the values of the variables scheme, ss58Prefix & publicKey.
* It also returns the network name.
*
* @param address ss58 or hex address to validate
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
* @param scheme
* @param ss58Prefix
* @param publicKey
*/
accountConvert(
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
accountId: string,
scheme: KeypairType,
ss58Prefix: number,
publicKey: boolean
): IAccountConvert {
const accountIdIsHex = isHex(accountId);
if (!accountIdIsHex) {
throw new BadRequest('`accountId` is not a valid hex value.');
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
}
let network = null;
for (const networkParams of allNetworks) {
if (networkParams['prefix'] === ss58Prefix) {
network = networkParams['network'];
break;
}
}
Comment on lines +49 to +55
Copy link
Collaborator

@jsdw jsdw Sep 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming allNetworks is an array, you can also do:

let network = allNetworks.find(n => n['prefix'] === ss58Prefix);
if (!network) {
   throw new BadRequest(...)
}

Not a big deal though :)

if (network === null) {
throw new BadRequest(
'`prefix` does not correspond to a existing network.'
Imod7 marked this conversation as resolved.
Show resolved Hide resolved
);
}

const keyring = new Keyring({ type: scheme, ss58Format: ss58Prefix });
const address = keyring.encodeAddress(accountId, ss58Prefix);

return {
ss58Prefix,
network,
address,
accountId,
scheme,
publicKey,
};
}
}
1 change: 1 addition & 0 deletions src/services/accounts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

export * from './AccountsAssetsService';
export * from './AccountsBalanceInfoService';
export * from './AccountsConvertService';
export * from './AccountsStakingInfoService';
export * from './AccountsStakingPayoutsService';
export * from './AccountsValidateService';
Expand Down
24 changes: 24 additions & 0 deletions src/types/responses/AccountConvert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

export interface IAccountConvert {
ss58Prefix: number | null;
network: string | null;
address: string | null;
accountId: string | null;
scheme: string | null;
publicKey: boolean;
}
1 change: 1 addition & 0 deletions src/types/responses/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

export * from './AccountAssets';
export * from './AccountBalanceInfo';
export * from './AccountConvert';
export * from './AccountStakingInfo';
export * from './AccountStakingPayouts';
export * from './AccountVestingInfo';
Expand Down