From d97119ba509ab583ccc0f2b20e7fd2abc8b329b7 Mon Sep 17 00:00:00 2001 From: Adil Iqbal Date: Thu, 27 Apr 2023 17:52:19 +0200 Subject: [PATCH] Feature: Added support for rootstock protocol --- src/app/models/ActionGroup.ts | 36 +++++++++++++++++++ src/app/pages/exchange/exchange.ts | 5 +++ .../pages/health-check/health-check.page.ts | 13 +++++-- .../transaction-prepare.ts | 3 ++ .../pages/walletconnect/walletconnect.page.ts | 5 +-- src/app/services/coinlib/coinlib.service.ts | 2 +- src/app/services/guard/protocol.guard.ts | 2 +- src/app/services/iac/iac.service.ts | 2 +- src/app/services/operations/operations.ts | 2 ++ src/app/services/price/price.service.ts | 5 ++- src/assets/workers/airgap-coin-lib.js | 1 + 11 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/app/models/ActionGroup.ts b/src/app/models/ActionGroup.ts index 2ff6c21e6..0752aa758 100644 --- a/src/app/models/ActionGroup.ts +++ b/src/app/models/ActionGroup.ts @@ -45,6 +45,9 @@ export class ActionGroup { actionMap.set(MainProtocolSymbols.ETH, async () => { return this.getEthereumActions() }) + actionMap.set(MainProtocolSymbols.RBTC, async () => { + return this.getRskActions() + }) actionMap.set(MainProtocolSymbols.COSMOS, async () => { return this.getCosmosActions() }) @@ -251,6 +254,39 @@ export class ActionGroup { return [addTokenButtonAction] } + private getRskActions(): Action[] { + const addTokenButtonAction: ButtonAction = new ButtonAction( + { name: 'account-transaction-list.add-tokens_label', icon: 'add-outline', identifier: 'add-tokens' }, + () => { + const prepareAddTokenActionContext: SimpleAction = new SimpleAction(() => { + return new Promise(resolve => { + const info = { + subProtocolType: SubProtocolType.TOKEN, + wallet: this.callerContext.wallet, + actionCallback: resolve + } + this.callerContext.dataService.setData(DataServiceKey.DETAIL, info) + this.callerContext.router + .navigateByUrl( + `/sub-account-add/${DataServiceKey.DETAIL}/${info.wallet.publicKey}/${info.wallet.protocol.identifier}/${ + info.wallet.addressIndex + }/${info.subProtocolType}` + ) + .catch(handleErrorSentry(ErrorCategory.NAVIGATION)) + }) + }) + const addTokenAction: LinkedAction = new LinkedAction(prepareAddTokenActionContext, AddTokenAction) + addTokenAction.onComplete = async (): Promise => { + addTokenAction.getLinkedAction().context.location.navigateRoot('') + } + + return addTokenAction + } + ) + + return [addTokenButtonAction] + } + private getPolkadotActions(): Action[] { const delegateButtonAction = this.createDelegateButtonAction() diff --git a/src/app/pages/exchange/exchange.ts b/src/app/pages/exchange/exchange.ts index c899dfff2..e669acf57 100644 --- a/src/app/pages/exchange/exchange.ts +++ b/src/app/pages/exchange/exchange.ts @@ -9,6 +9,7 @@ import { ProtocolSymbols, SubProtocolSymbols } from '@airgap/coinlib-core' +import { RskProtocol } from '@airgap/rsk' import { NetworkType } from '@airgap/coinlib-core/utils/ProtocolNetwork' import { EthereumProtocol } from '@airgap/ethereum' import { Component, NgZone, OnDestroy, OnInit } from '@angular/core' @@ -361,6 +362,10 @@ export class ExchangePage implements OnInit, OnDestroy { feeCurrentMarketPrice = await this.priceService .getCurrentMarketPrice(new TezosProtocol(), 'USD') .then((price: BigNumber) => price.toNumber()) + } else if (this.selectedFromProtocol.identifier.startsWith(SubProtocolSymbols.RBTC_ERC20)) { + feeCurrentMarketPrice = this.priceService + .getCurrentMarketPrice(new RskProtocol(), 'USD') + .then((price: BigNumber) => price.toNumber()) } else { feeCurrentMarketPrice = (await this.priceService.getCurrentMarketPrice(this.selectedFromProtocol, 'USD')).toNumber() } diff --git a/src/app/pages/health-check/health-check.page.ts b/src/app/pages/health-check/health-check.page.ts index 2439ef04b..46c290b7c 100644 --- a/src/app/pages/health-check/health-check.page.ts +++ b/src/app/pages/health-check/health-check.page.ts @@ -23,6 +23,13 @@ interface CheckItem { check: () => Promise } +// TODO: Should be provided by the API + const rskHealthMock = { + identifier: MainProtocolSymbols.RBTC, + node: { isHealthy: true }, + explorer: { isHealthy: true } + } + @Component({ selector: 'app-health-check', templateUrl: './health-check.page.html', @@ -45,6 +52,8 @@ export class HealthCheckPage { this.generateCheckItem('Bitcoin', MainProtocolSymbols.BTC, ApiType.NODE), this.generateCheckItem('Ethereum', MainProtocolSymbols.ETH, ApiType.NODE), this.generateCheckItem('Ethereum', MainProtocolSymbols.ETH, ApiType.Explorer), + this.generateCheckItem('RSK', MainProtocolSymbols.RBTC, ApiType.NODE), + this.generateCheckItem('RSK', MainProtocolSymbols.RBTC, ApiType.Explorer), this.generateCheckItem('Polkadot', MainProtocolSymbols.POLKADOT, ApiType.NODE), this.generateCheckItem('Polkadot', MainProtocolSymbols.POLKADOT, ApiType.Explorer), this.generateCheckItem('Kusama', MainProtocolSymbols.KUSAMA, ApiType.NODE), @@ -58,8 +67,8 @@ export class HealthCheckPage { public async ionViewWillEnter() { this.displayLoading() this.coinlibService.checkApiHealth().then((apiHealth) => { - this.apiHealth = apiHealth - this.loadingElement.dismiss() + this.apiHealth = apiHealth.concat(rskHealthMock) // TODO: Api result instead of mock + this.loadingElement?.dismiss() this.runChecks() }) } diff --git a/src/app/pages/transaction-prepare/transaction-prepare.ts b/src/app/pages/transaction-prepare/transaction-prepare.ts index 9a71397c2..88d3fdc78 100644 --- a/src/app/pages/transaction-prepare/transaction-prepare.ts +++ b/src/app/pages/transaction-prepare/transaction-prepare.ts @@ -3,6 +3,7 @@ import { AirGapMarketWallet, AirGapNFTWallet, MainProtocolSymbols, SubProtocolSy import { FeeDefaults } from '@airgap/coinlib-core/protocols/ICoinProtocol' import { NetworkType } from '@airgap/coinlib-core/utils/ProtocolNetwork' import { EthereumProtocol } from '@airgap/ethereum' +import { RskProtocol } from '@airgap/rsk' import { IACMessageType } from '@airgap/serializer' import { SubstrateProtocol } from '@airgap/substrate' import { TezosProtocol } from '@airgap/tezos' @@ -401,6 +402,8 @@ export class TransactionPreparePage { return this.priceService.getCurrentMarketPrice(new TezosProtocol(), 'USD').then((price: BigNumber) => price.toNumber()) } else if (wallet.protocol.identifier.startsWith(SubProtocolSymbols.ETH_ERC20)) { return this.priceService.getCurrentMarketPrice(new EthereumProtocol(), 'USD').then((price: BigNumber) => price.toNumber()) + } else if (wallet.protocol.identifier.startsWith(SubProtocolSymbols.RBTC_ERC20)) { + return this.priceService.getCurrentMarketPrice(new RskProtocol(), 'USD').then((price: BigNumber) => price.toNumber()) } else { return wallet.getCurrentMarketPrice(this.collectibleID)?.toNumber() ?? 0 } diff --git a/src/app/pages/walletconnect/walletconnect.page.ts b/src/app/pages/walletconnect/walletconnect.page.ts index 04dd6b1fe..ff3aebb5f 100644 --- a/src/app/pages/walletconnect/walletconnect.page.ts +++ b/src/app/pages/walletconnect/walletconnect.page.ts @@ -89,8 +89,9 @@ export class WalletconnectPage implements OnInit { public async ngOnInit(): Promise { this.subscription = this.accountService.allWallets$.asObservable().subscribe((wallets: AirGapMarketWallet[]) => { this.selectableWallets = wallets.filter( - (wallet: AirGapMarketWallet) => - wallet.protocol.identifier === MainProtocolSymbols.ETH && wallet.status === AirGapWalletStatus.ACTIVE + (wallet: AirGapMarketWallet) => + (wallet.protocol.identifier === MainProtocolSymbols.ETH || wallet.protocol.identifier === MainProtocolSymbols.RBTC) && + wallet.status === AirGapWalletStatus.ACTIVE ) if (this.selectableWallets.length > 0) { this.selectedWallet = this.selectableWallets[0] diff --git a/src/app/services/coinlib/coinlib.service.ts b/src/app/services/coinlib/coinlib.service.ts index 50dfac7f2..56a6120fd 100644 --- a/src/app/services/coinlib/coinlib.service.ts +++ b/src/app/services/coinlib/coinlib.service.ts @@ -24,7 +24,7 @@ export interface ApiHealth { isHealthy: boolean errorDescription?: string } - blockExplorer?: { + explorer?: { isHealthy: boolean errorDescription?: string } diff --git a/src/app/services/guard/protocol.guard.ts b/src/app/services/guard/protocol.guard.ts index 1ea3d8a02..610ae296b 100644 --- a/src/app/services/guard/protocol.guard.ts +++ b/src/app/services/guard/protocol.guard.ts @@ -20,7 +20,7 @@ export class ProtocolGuard implements CanActivate { let subSymbols: string[] = Object.values(SubProtocolSymbols).map((p: SubProtocolSymbols) => p.toString()) if (mainProtocolID !== undefined) { - if (mainProtocolID === MainProtocolSymbols.ETH || mainProtocolID === MainProtocolSymbols.XTZ) { + if (mainProtocolID === MainProtocolSymbols.ETH || mainProtocolID === MainProtocolSymbols.RBTC || mainProtocolID === MainProtocolSymbols.XTZ) { subSymbols = (await this.protocolService.getAllSubProtocols(mainProtocolID)).map((protocol: ICoinProtocol) => protocol.identifier.toString() ) diff --git a/src/app/services/iac/iac.service.ts b/src/app/services/iac/iac.service.ts index a4041d93a..a7ee84f7c 100644 --- a/src/app/services/iac/iac.service.ts +++ b/src/app/services/iac/iac.service.ts @@ -144,7 +144,7 @@ export class IACService extends BaseIACService { signature: messageSignResponse.signature, signingType: SigningType.RAW } - if (protocol === MainProtocolSymbols.XTZ) { + if (protocol === MainProtocolSymbols.XTZ || protocol === MainProtocolSymbols.RBTC) { await this.beaconService.respond(response, cachedRequest[0]) } else if (protocol === MainProtocolSymbols.ETH) { await this.walletConnectService.approveRequest(response.id, response.signature) diff --git a/src/app/services/operations/operations.ts b/src/app/services/operations/operations.ts index be4b107fc..4c09fc119 100644 --- a/src/app/services/operations/operations.ts +++ b/src/app/services/operations/operations.ts @@ -15,6 +15,7 @@ import { SubProtocolSymbols } from '@airgap/coinlib-core' import { CosmosTransaction } from '@airgap/cosmos' +import { RawRskTransaction } from '@airgap/rsk' import { RawEthereumTransaction } from '@airgap/ethereum' import { IACMessageDefinitionObjectV3, IACMessageType } from '@airgap/serializer' import { RawSubstrateTransaction } from '@airgap/substrate' @@ -43,6 +44,7 @@ import { ErrorCategory, handleErrorSentry } from '../sentry-error-handler/sentry export type SerializableTx = | RawTezosTransaction | RawEthereumTransaction + | RawRskTransaction | RawBitcoinTransaction | RawAeternityTransaction | CosmosTransaction diff --git a/src/app/services/price/price.service.ts b/src/app/services/price/price.service.ts index cbfeb1579..b7402dd3c 100644 --- a/src/app/services/price/price.service.ts +++ b/src/app/services/price/price.service.ts @@ -218,7 +218,10 @@ export class PriceService implements AirGapWalletPriceService { yfi: 'yearn-finance', zb: 'zb-token', zil: 'zilliqa', - xchf: 'cryptofranc' + xchf: 'cryptofranc', + rbtc: 'rootstock', + rif: 'rif-token', + sov: 'sovryn' } const id = symbolMapping[protocol.marketSymbol.toLowerCase()] diff --git a/src/assets/workers/airgap-coin-lib.js b/src/assets/workers/airgap-coin-lib.js index a53cad951..ef46bc348 100644 --- a/src/assets/workers/airgap-coin-lib.js +++ b/src/assets/workers/airgap-coin-lib.js @@ -19,6 +19,7 @@ const protocols = [ new airgapCoinLibBitcoin.BitcoinProtocol(), new airgapCoinLibBitcoin.BitcoinSegwitProtocol(), new airgapCoinLibEthereum.EthereumProtocol(), + new airgapCoinLib.addSupportedProtocol(new airgapCoinLib.RskProtocol()), new airgapCoinLibGroestlcoin.GroestlcoinProtocol(), new airgapCoinLibTezos.TezosProtocol(), new airgapCoinLibCosmos.CosmosProtocol(),