Skip to content

Commit

Permalink
Merge pull request #181 from Cryptorubic/develop
Browse files Browse the repository at this point in the history
Rango integration
  • Loading branch information
ko1ebayev authored Sep 2, 2022
2 parents 7618608 + 8daad78 commit b568a98
Show file tree
Hide file tree
Showing 23 changed files with 1,528 additions and 700 deletions.
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rubic-sdk",
"version": "2.13.2",
"version": "2.14.0",
"description": "Simplify dApp creation",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down Expand Up @@ -69,22 +69,23 @@
"bignumber.js": "9.1.0",
"bitcoin-address-validation": "2.2.1",
"ethers": "^5.6.8",
"rango-sdk-basic": "^0.0.7",
"rxjs": "^7.5.5",
"symbiosis-js-sdk": "2.8.13",
"web3": "~1.7.3"
},
"devDependencies": {
"@babel/core": "^7.0.0-0",
"@types/jest": "^28.1.2",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"bip39": "^3.0.4",
"cancelable-promise": "^4.2.1",
"commander": "^8.3.0",
"compression-webpack-plugin": "^9.2.0",
"crypto-browserify": "^3.12.0",
"delay": "^5.0.0",
"eslint": "^7.25.0",
"eslint": "^8.23.0",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.22.1",
Expand Down
1 change: 1 addition & 0 deletions src/features/cross-chain/constants/bridge-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const BRIDGE_TYPE = {

HOP: 'hop',
HYPHEN: 'hyphen',
OPEN_OCEAN: 'openocean',

MAKERS_WORMHOLE: 'maker',
MULTICHAIN: 'multichain',
Expand Down
14 changes: 10 additions & 4 deletions src/features/cross-chain/cross-chain-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { CelerCrossChainTradeProvider } from '@rsdk-features/cross-chain/provide
import { CcrTypedTradeProviders } from '@rsdk-features/cross-chain/models/typed-trade-provider';
import {
CelerCrossChainTrade,
CelerRubicCrossChainTrade,
CROSS_CHAIN_TRADE_TYPE,
CrossChainTradeType,
SymbiosisCrossChainTrade
RangoCrossChainTradeProvider,
CelerRubicCrossChainTrade,
SymbiosisCrossChainTrade,
RangoCrossChainTrade
} from 'src/features';
import { SwapManagerCrossChainCalculationOptions } from '@rsdk-features/cross-chain/models/swap-manager-cross-chain-options';
import pTimeout from '@rsdk-common/utils/p-timeout';
Expand All @@ -36,6 +38,7 @@ import { LifiCrossChainTradeProvider } from 'src/features/cross-chain/providers/
import { RubicCrossChainTradeProvider } from 'src/features/cross-chain/providers/rubic-trade-provider/rubic-cross-chain-trade-provider';
import { ViaCrossChainTrade } from 'src/features/cross-chain/providers/via-trade-provider/via-cross-chain-trade';
import { DebridgeCrossChainTrade } from 'src/features/cross-chain/providers/debridge-trade-provider/debridge-cross-chain-trade';
import { Injector } from 'src/core/sdk/injector';

type RequiredSwapManagerCalculationOptions = MarkRequired<
SwapManagerCrossChainCalculationOptions,
Expand All @@ -59,6 +62,7 @@ export class CrossChainManager {
SymbiosisCrossChainTradeProvider,
LifiCrossChainTradeProvider,
DebridgeCrossChainTradeProvider,
RangoCrossChainTradeProvider,
ViaCrossChainTradeProvider
].reduce((acc, ProviderClass) => {
const provider = new ProviderClass();
Expand Down Expand Up @@ -318,7 +322,8 @@ export class CrossChainManager {
fromUsd = prevTrade.transitAmount;
} else if (
prevTrade instanceof LifiCrossChainTrade ||
prevTrade instanceof ViaCrossChainTrade
prevTrade instanceof ViaCrossChainTrade ||
prevTrade instanceof RangoCrossChainTrade
) {
fromUsd = prevTrade.from.price.multipliedBy(prevTrade.from.tokenAmount);
} else {
Expand Down Expand Up @@ -350,7 +355,8 @@ export class CrossChainManager {
timeout: CrossChainManager.defaultCalculationTimeout,
providerAddress: this.providerAddress,
slippageTolerance: CrossChainManager.defaultSlippageTolerance * 2,
deadline: CrossChainManager.defaultDeadline
deadline: CrossChainManager.defaultDeadline,
toAddress: Injector.web3Private.address
});
}

Expand Down
59 changes: 58 additions & 1 deletion src/features/cross-chain/cross-chain-status-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BLOCKCHAIN_NAME, BlockchainName, BlockchainsInfo } from 'src/core';
import { Injector } from 'src/core/sdk/injector';
import { celerCrossChainEventStatusesAbi } from 'src/features/cross-chain/providers/celer-trade-provider/constants/celer-cross-chain-event-statuses-abi';
import { LogsDecoder } from 'src/features/cross-chain/utils/decode-logs';
import { StatusResponse, TransactionStatus } from 'rango-sdk-basic/lib';
import { Via } from '@viaprotocol/router-sdk';
import { VIA_DEFAULT_CONFIG } from 'src/features/cross-chain/providers/via-trade-provider/constants/via-default-api-key';
import { ViaSwapStatus } from 'src/features/cross-chain/providers/via-trade-provider/models/via-swap-status';
Expand All @@ -21,6 +22,7 @@ import { LifiSwapStatus } from './providers/lifi-trade-provider/models/lifi-swap
import { SymbiosisSwapStatus } from './providers/symbiosis-trade-provider/models/symbiosis-swap-status';
import { CrossChainTradeData } from './models/cross-chain-trade-data';
import { RubicCrossChainSupportedBlockchain } from './providers/rubic-trade-provider/constants/rubic-cross-chain-supported-blockchains';
import { RANGO_API_KEY } from './providers/rango-trade-provider/constants/rango-api-key';
import {
BtcStatusResponse,
DeBridgeApiResponse,
Expand All @@ -40,7 +42,8 @@ export class CrossChainStatusManager {
[CROSS_CHAIN_TRADE_TYPE.LIFI]: this.getLifiDstSwapStatus,
[CROSS_CHAIN_TRADE_TYPE.SYMBIOSIS]: this.getSymbiosisDstSwapStatus,
[CROSS_CHAIN_TRADE_TYPE.DEBRIDGE]: this.getDebridgeDstSwapStatus,
[CROSS_CHAIN_TRADE_TYPE.VIA]: this.getViaDstSwapStatus
[CROSS_CHAIN_TRADE_TYPE.VIA]: this.getViaDstSwapStatus,
[CROSS_CHAIN_TRADE_TYPE.RANGO]: this.getRangoDstSwapStatus
};

/**
Expand Down Expand Up @@ -136,6 +139,60 @@ export class CrossChainStatusManager {
return await this.getDstTxStatusFnMap[provider].call(this, tradeData, srcTxReceipt);
}

/**
* Get Rango trade dst transaction status.
* @param data Trade data.
* @param srcTxReceipt Source transaction receipt.
* @returns Cross-chain transaction status.
*/
private async getRangoDstSwapStatus(
data: CrossChainTradeData,
srcTxReceipt: TransactionReceipt
): Promise<CrossChainTxStatus> {
try {
const { rangoRequestId: requestId } = data;
const rangoTradeStatusResponse = await Injector.httpClient.get<StatusResponse>(
'https://api.rango.exchange/basic/status',
{
params: {
apiKey: RANGO_API_KEY,
requestId: requestId as string,
txId: srcTxReceipt.transactionHash
}
}
);

if (rangoTradeStatusResponse.status === TransactionStatus.SUCCESS) {
return CrossChainTxStatus.SUCCESS;
}

if (rangoTradeStatusResponse.status === TransactionStatus.FAILED) {
const type = rangoTradeStatusResponse?.output?.type;

if (type === 'MIDDLE_ASSET_IN_SRC' || type === 'MIDDLE_ASSET_IN_DEST') {
return CrossChainTxStatus.FALLBACK;
}

if (type === 'REVERTED_TO_INPUT') {
return CrossChainTxStatus.REVERT;
}

return CrossChainTxStatus.FAIL;
}

if (
rangoTradeStatusResponse.status === TransactionStatus.RUNNING ||
rangoTradeStatusResponse.status === null
) {
return CrossChainTxStatus.PENDING;
}

return CrossChainTxStatus.UNKNOWN;
} catch {
return CrossChainTxStatus.PENDING;
}
}

/**
* Get Symbiosis trade dst transaction status.
* @param data Trade data.
Expand Down
2 changes: 2 additions & 0 deletions src/features/cross-chain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export { RubicCrossChainTrade } from './providers/rubic-trade-provider/rubic-cro
export { CelerCrossChainTrade } from './providers/celer-trade-provider/celer-cross-chain-trade';
export { SymbiosisCrossChainTrade } from './providers/symbiosis-trade-provider/symbiosis-cross-chain-trade';
export { LifiCrossChainTrade } from './providers/lifi-trade-provider/lifi-cross-chain-trade';
export { RangoCrossChainTrade } from './providers/rango-trade-provider/rango-cross-chain-trade';
export { RangoCrossChainTradeProvider } from './providers/rango-trade-provider/rango-cross-chain-trade-provider';

export { CROSS_CHAIN_TRADE_TYPE, CrossChainTradeType } from './models/cross-chain-trade-type';
export { CrossChainTradeData } from './models/cross-chain-trade-data';
Expand Down
6 changes: 6 additions & 0 deletions src/features/cross-chain/models/cross-chain-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ export interface CrossChainOptions {
* Timeout for each cross chain provider. Calculation for provider is cancelled, after timeout is passed.
*/
readonly timeout?: number;

/**
* Receiver address, otherwise connected wallet is used (necessary for Rango).
*/
toAddress?: string;
}

export type RequiredCrossChainOptions = MarkRequired<
Expand All @@ -59,4 +64,5 @@ export type RequiredCrossChainOptions = MarkRequired<
| 'deadline'
| 'providerAddress'
| 'timeout'
| 'toAddress'
>;
5 changes: 5 additions & 0 deletions src/features/cross-chain/models/cross-chain-trade-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@ export interface CrossChainTradeData {
* Via action uuid.
*/
viaUuid?: string;

/**
* Rango request id
*/
rangoRequestId?: string;
}
3 changes: 2 additions & 1 deletion src/features/cross-chain/models/cross-chain-trade-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export const CROSS_CHAIN_TRADE_TYPE = {
SYMBIOSIS: 'SYMBIOSIS',
LIFI: 'LIFI',
DEBRIDGE: 'DEBRIDGE',
VIA: 'VIA'
VIA: 'VIA',
RANGO: 'RANGO'
} as const;

export type CrossChainTradeType = keyof typeof CROSS_CHAIN_TRADE_TYPE;
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,12 @@ export const commonCrossChainAbi: AbiItem[] = [
outputs: [],
stateMutability: 'payable',
type: 'function'
},
{
inputs: [],
name: 'getAvailableRouters',
outputs: [{ internalType: 'address[]', name: '', type: 'address[]' }],
stateMutability: 'view',
type: 'function'
}
];
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { RequiredCrossChainOptions } from '@rsdk-features/cross-chain/models/cro
import { PriceTokenAmount } from '@rsdk-core/blockchain/tokens/price-token-amount';
import { PriceToken } from '@rsdk-core/blockchain/tokens/price-token';
import { WrappedCrossChainTrade } from '@rsdk-features/cross-chain/providers/common/models/wrapped-cross-chain-trade';
import { RubicSdkError } from 'src/common';
import { CrossChainIsUnavailableError, RubicSdkError } from 'src/common';
import { parseError } from 'src/common/utils/errors';
import { BlockchainName, Web3Pure } from 'src/core';
import { FeeInfo } from 'src/features/cross-chain/providers/common/models/fee';
import { Injector } from 'src/core/sdk/injector';
import { EMPTY_ADDRESS } from 'src/core/blockchain/constants/empty-address';
import { AbiItem } from 'web3-utils';
import BigNumber from 'bignumber.js';
import { commonCrossChainAbi } from './constants/common-cross-chain-abi';

export abstract class CrossChainTradeProvider {
public static parseError(err: unknown): RubicSdkError {
Expand Down Expand Up @@ -120,6 +121,23 @@ export abstract class CrossChainTradeProvider {
);
}

protected async checkContractState(
fromBlockchain: BlockchainName,
rubicRouter: string
): Promise<void> {
const web3PublicService = Injector.web3PublicService.getWeb3Public(fromBlockchain);

const isPaused = await web3PublicService.callContractMethod<number>(
rubicRouter,
commonCrossChainAbi,
'paused'
);

if (isPaused) {
throw new CrossChainIsUnavailableError();
}
}

public abstract isSupportedBlockchains(
fromBlockchain: BlockchainName,
toBlockchain: BlockchainName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { CROSS_CHAIN_TRADE_TYPE } from 'src/features';
import { BlockchainName, BlockchainsInfo, PriceToken, Web3Pure } from 'src/core';
import { RequiredCrossChainOptions } from '@rsdk-features/cross-chain/models/cross-chain-options';

import { CrossChainIsUnavailableError } from 'src/common';
import { Injector } from '@rsdk-core/sdk/injector';
import { PriceTokenAmount } from '@rsdk-core/blockchain/tokens/price-token-amount';
import { WrappedCrossChainTrade } from '@rsdk-features/cross-chain/providers/common/models/wrapped-cross-chain-trade';
Expand Down Expand Up @@ -67,7 +66,10 @@ export class DebridgeCrossChainTradeProvider extends CrossChainTradeProvider {
try {
const fromAddress = options.fromAddress || this.walletAddress;

await this.checkContractState(fromBlockchain);
await this.checkContractState(
fromBlockchain,
DE_BRIDGE_CONTRACT_ADDRESS[fromBlockchain].rubicRouter
);

const feeInfo = await this.getFeeInfo(fromBlockchain, options.providerAddress);

Expand Down Expand Up @@ -159,21 +161,7 @@ export class DebridgeCrossChainTradeProvider extends CrossChainTradeProvider {
}
}

private async checkContractState(fromBlockchain: DeBridgeCrossChainSupportedBlockchain) {
const web3PublicService = Injector.web3PublicService.getWeb3Public(fromBlockchain);

const isPaused = await web3PublicService.callContractMethod<number>(
DE_BRIDGE_CONTRACT_ADDRESS[fromBlockchain].rubicRouter,
commonCrossChainAbi,
'paused'
);

if (isPaused) {
throw new CrossChainIsUnavailableError();
}
}

protected override async getFeeInfo(
protected async getFeeInfo(
fromBlockchain: DeBridgeCrossChainSupportedBlockchain,
providerAddress: string
): Promise<FeeInfo> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ import {
} from 'src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-cross-chain-supported-blockchain';
import LIFI, { Route, RouteOptions } from '@lifi/sdk';
import { LifiCrossChainTrade } from 'src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade';
import { Injector } from 'src/core/sdk/injector';
import { WrappedCrossChainTrade } from 'src/features/cross-chain/providers/common/models/wrapped-cross-chain-trade';
import { CrossChainTradeProvider } from 'src/features/cross-chain/providers/common/cross-chain-trade-provider';
import { RequiredCrossChainOptions } from 'src/features/cross-chain/models/cross-chain-options';
import { lifiContractAddress } from 'src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-contract-data';
import { PriceTokenAmount } from 'src/core/blockchain/tokens/price-token-amount';
import { getLifiConfig } from 'src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-config';
import { CrossChainIsUnavailableError } from 'src/common';
import { CrossChainMinAmountError } from 'src/common/errors/cross-chain/cross-chain-min-amount.error';
import { FeeInfo } from 'src/features/cross-chain/providers/common/models/fee';
import { nativeTokensList } from 'src/core/blockchain/constants/native-tokens';
Expand Down Expand Up @@ -63,7 +61,10 @@ export class LifiCrossChainTradeProvider extends CrossChainTradeProvider {
return null;
}

await this.checkContractState(fromBlockchain);
await this.checkContractState(
fromBlockchain,
lifiContractAddress[fromBlockchain].rubicRouter
);

const feeInfo = await this.getFeeInfo(fromBlockchain, options.providerAddress, from);

Expand Down Expand Up @@ -155,20 +156,6 @@ export class LifiCrossChainTradeProvider extends CrossChainTradeProvider {
};
}

private async checkContractState(fromBlockchain: LifiCrossChainSupportedBlockchain) {
const web3PublicService = Injector.web3PublicService.getWeb3Public(fromBlockchain);

const isPaused = await web3PublicService.callContractMethod<number>(
lifiContractAddress[fromBlockchain].rubicRouter,
commonCrossChainAbi,
'paused'
);

if (isPaused) {
throw new CrossChainIsUnavailableError();
}
}

private checkMinError(from: PriceTokenAmount): void | never {
if (from.price.multipliedBy(from.tokenAmount).lt(this.MIN_AMOUNT_USD)) {
throw new CrossChainMinAmountError(this.MIN_AMOUNT_USD, 'USDC');
Expand Down
Loading

0 comments on commit b568a98

Please sign in to comment.