diff --git a/CHANGELOG.md b/CHANGELOG.md index ffd5ab23..10c9fff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ # Changelog +## [1.7.1] - 2024-04-12 +### New +- Added `getSupportedAssets` to get supported tokens +- Added `getQuotes` to get transaction quotes +- Added `getTransactionStatus` to get the transaction status +- The default provider is `Connext` ## [1.7.0] - 2024-04-10 ### New diff --git a/examples/25-get-quotes.ts b/examples/25-get-quotes.ts new file mode 100644 index 00000000..cf7ab8c4 --- /dev/null +++ b/examples/25-get-quotes.ts @@ -0,0 +1,46 @@ +import { utils } from 'ethers'; +import { DataUtils } from '../src'; +import * as dotenv from 'dotenv'; +import { BridgingProvider } from '../src/sdk/data'; + +dotenv.config(); +const dataApiKey = ''; + +async function main(): Promise { + // initializating Data service... + const dataService = new DataUtils(dataApiKey); + + const allSupportedAssets = await dataService.getSupportedAssets({}); + // the default provider is Connext + console.log('\x1b[33m%s\x1b[0m', `All supported assets:`, allSupportedAssets.length); + + const supportedAssets = await dataService.getSupportedAssets({ + chainId: 1, + provider: BridgingProvider.Connext, + }); + console.log('\x1b[33m%s\x1b[0m', `Connext supported assets per chain:`, supportedAssets.length); + + const quotes = await dataService.getQuotes({ + fromAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + toAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + fromChainId: 1, + toChainId: 10, + fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + fromAmount: utils.parseUnits('1', 18), + slippage: 0.1, + provider: BridgingProvider.Connext, + }); + console.log('\x1b[33m%s\x1b[0m', `Connext quote transactions:`, quotes); + + const transactionStatus = await dataService.getTransactionStatus({ + fromChainId: 100, + toChainId: 56, + transactionHash: '0xfc46adedf462d3fd6cdbe0214ed11c06cba20c385b9875aa4d51c60afbd9725d', + provider: BridgingProvider.Connext, + }); + console.log('\x1b[33m%s\x1b[0m', `Connext transaction status:`, transactionStatus); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/package-lock.json b/package-lock.json index 723c812d..6ce897ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@etherspot/prime-sdk", - "version": "1.7.0", + "version": "1.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@etherspot/prime-sdk", - "version": "1.7.0", + "version": "1.7.1", "license": "MIT", "dependencies": { "@apollo/client": "3.8.7", diff --git a/package.json b/package.json index f0bd0473..2ce88861 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@etherspot/prime-sdk", - "version": "1.7.0", + "version": "1.7.1", "description": "Etherspot Prime (Account Abstraction) SDK", "keywords": [ "ether", @@ -42,6 +42,7 @@ "20-callGasLimit": "./node_modules/.bin/ts-node ./examples/20-callGasLimit", "21-get-multiple-accounts": "./node_modules/.bin/ts-node ./examples/21-get-multiple-accounts", "22-concurrent-userops": "./node_modules/.bin/ts-node ./examples/22-concurrent-userops", + "25-get-quotes": "./node_modules/.bin/ts-node ./examples/25-get-quotes", "format": "prettier --write \"{src,test,examples}/**/*.ts\"", "lint": "eslint \"{src,test,examples}/**/*.ts\"", "lint-fix": "npm run lint -- --fix", diff --git a/src/sdk/api/constants.ts b/src/sdk/api/constants.ts index a4230c6a..41e82dd1 100644 --- a/src/sdk/api/constants.ts +++ b/src/sdk/api/constants.ts @@ -19,6 +19,9 @@ export const API_ENDPOINTS = { GET_ADVANCE_ROUTES_LIFI: 'exchange/getAdvanceRoutesLiFi', GET_STEP_TRANSACTIONS: 'exchange/getStepTransactions', GET_EXCHANGE_OFFERS: 'exchange/offers', + GET_CONNEXT_SUPPORTED_ASSETS: 'exchange/connext/supportedAssets', + GET_CONNEXT_QUOTE_TRANSACTIONS: 'exchange/connext/quoteTransactions', + GET_CONNEXT_TRANSACTION_STATUS: 'exchange/connext/transactionStatus', GET_EXCHANGE_SUPPORTED_ASSETS: 'assets/exchangeSupportedAssets', GET_TOKEN_LISTS: 'assets/tokenLists', GET_TOKEN_LIST_TOKENS: 'assets/tokenListTokens', diff --git a/src/sdk/data/classes/index.ts b/src/sdk/data/classes/index.ts index fc2bd0ce..4c3eaa65 100644 --- a/src/sdk/data/classes/index.ts +++ b/src/sdk/data/classes/index.ts @@ -24,3 +24,6 @@ export * from './token-lists'; export * from './token-list-token'; export * from './paginated-tokens'; export * from './transactions'; +export * from './token'; +export * from './quote'; +export * from './transaction-status'; diff --git a/src/sdk/data/classes/quote.ts b/src/sdk/data/classes/quote.ts new file mode 100644 index 00000000..c0938210 --- /dev/null +++ b/src/sdk/data/classes/quote.ts @@ -0,0 +1,10 @@ +import { BigNumberish, BytesLike } from "ethers"; + +export class Quote { + to?: string; + data?: BytesLike; + value?: BigNumberish; + gasLimit?: string; + gasPrice?: string; + chainId?: number; +} diff --git a/src/sdk/data/classes/token.ts b/src/sdk/data/classes/token.ts new file mode 100644 index 00000000..3a30d5df --- /dev/null +++ b/src/sdk/data/classes/token.ts @@ -0,0 +1,8 @@ +export class Token { + symbol: string; + address: string; + decimals: number; + chainId: number; + name: string; + icon: string; +} diff --git a/src/sdk/data/classes/transaction-status.ts b/src/sdk/data/classes/transaction-status.ts new file mode 100644 index 00000000..5d216d93 --- /dev/null +++ b/src/sdk/data/classes/transaction-status.ts @@ -0,0 +1,6 @@ +export class TransactionStatus { + status: string; + transactionHash?: string; + connextscanUrl: string; + transferId?: string; +} diff --git a/src/sdk/data/constants.ts b/src/sdk/data/constants.ts index 3772dae9..7891f58e 100644 --- a/src/sdk/data/constants.ts +++ b/src/sdk/data/constants.ts @@ -38,6 +38,10 @@ export enum CrossChainServiceProvider { Etherspot = 'Connext', } +export enum BridgingProvider { + Connext = 'Connext', +} + export enum LiFiBridge { across = 'across', arbitrum = 'arbitrum', diff --git a/src/sdk/data/data.module.ts b/src/sdk/data/data.module.ts index 40acb3ca..9e5ca6bb 100644 --- a/src/sdk/data/data.module.ts +++ b/src/sdk/data/data.module.ts @@ -1,9 +1,10 @@ import { BigNumber } from 'ethers'; import { Route } from '@lifi/sdk'; import { ObjectSubject } from '../common'; -import { AccountBalances, AdvanceRoutesLiFi, ExchangeOffer, NftList, PaginatedTokens, RateData, StepTransactions, TokenList, TokenListToken, Transaction, Transactions } from './classes'; +import { AccountBalances, AdvanceRoutesLiFi, Token, Quote, TransactionStatus, ExchangeOffer, NftList, PaginatedTokens, RateData, StepTransactions, TokenList, TokenListToken, Transaction, Transactions } from './classes'; import { RestApiService } from '../api'; import { API_ENDPOINTS, MethodTypes } from '../api/constants'; +import { BridgingProvider } from './constants'; export class DataModule { readonly apiKey$ = new ObjectSubject(''); @@ -249,4 +250,96 @@ export class DataModule { throw new Error(error.message || 'Failed to fetch exchange rates'); } } + + async getSupportedAssets(chainId?: number, provider?: BridgingProvider): Promise { + try { + const queryParams = { + 'api-key': this.currentApi, + chainId, + }; + let apiUrl: string; + + switch (provider) { + case BridgingProvider.Connext: + apiUrl = API_ENDPOINTS.GET_CONNEXT_SUPPORTED_ASSETS; + break; + default: + apiUrl = API_ENDPOINTS.GET_CONNEXT_SUPPORTED_ASSETS; + break; + } + + const result: { tokens: Token[] } = await this.apiService.makeRequest(apiUrl, MethodTypes.GET, queryParams); + + return result ? result.tokens : []; + } catch (error) { + throw new Error(error.message || 'Failed to get supported assets'); + } + } + + async getQuotes( + fromAddress: string, + toAddress: string, + fromChainId: number, + toChainId: number, + fromToken: string, + fromAmount: BigNumber, + slippage: number, + provider?: BridgingProvider + ): Promise { + try { + const queryParams = { + 'api-key': this.currentApi, + fromAddress, + toAddress, + fromChainId, + toChainId, + fromToken, + fromAmount: fromAmount.toString(), + slippage + }; + let apiUrl: string; + + switch (provider) { + case BridgingProvider.Connext: + apiUrl = API_ENDPOINTS.GET_CONNEXT_QUOTE_TRANSACTIONS; + break; + default: + apiUrl = API_ENDPOINTS.GET_CONNEXT_QUOTE_TRANSACTIONS; + break; + } + + const result: { transactions: Quote[] } = await this.apiService.makeRequest(apiUrl, MethodTypes.GET, queryParams); + + return result ? result.transactions : []; + } catch (error) { + throw new Error(error.message || 'Failed to get quotes transactions'); + } + } + + async getTransactionStatus(fromChainId: number, toChainId: number, transactionHash: string, provider?: BridgingProvider): Promise { + try { + const queryParams = { + 'api-key': this.currentApi, + fromChainId, + toChainId, + transactionHash, + }; + let apiUrl: string; + + switch (provider) { + case BridgingProvider.Connext: + apiUrl = API_ENDPOINTS.GET_CONNEXT_TRANSACTION_STATUS; + break; + default: + apiUrl = API_ENDPOINTS.GET_CONNEXT_TRANSACTION_STATUS; + break; + } + + const result: TransactionStatus = await this.apiService.makeRequest(apiUrl, MethodTypes.GET, queryParams); + + return result ? result : null; + } catch (error) { + throw new Error(error.message || 'Failed to get transaction status'); + } + } } diff --git a/src/sdk/dataUtils.ts b/src/sdk/dataUtils.ts index 9cc6cf7f..217b63f3 100644 --- a/src/sdk/dataUtils.ts +++ b/src/sdk/dataUtils.ts @@ -1,6 +1,6 @@ import "reflect-metadata"; -import { AccountBalances, AdvanceRoutesLiFi, DataModule, ExchangeOffer, NftList, PaginatedTokens, RateData, StepTransactions, TokenList, TokenListToken, Transaction, Transactions } from "./data"; -import { FetchExchangeRatesDto, GetAccountBalancesDto, GetAdvanceRoutesLiFiDto, GetExchangeOffersDto, GetExchangeSupportedAssetsDto, GetNftListDto, GetStepTransactionsLiFiDto, GetTokenListDto, GetTokenListsDto, GetTransactionDto, GetTransactionsDto, validateDto } from "./dto"; +import { AccountBalances, AdvanceRoutesLiFi, Token, Quote, TransactionStatus, DataModule, ExchangeOffer, NftList, PaginatedTokens, RateData, StepTransactions, TokenList, TokenListToken, Transaction, Transactions } from "./data"; +import { FetchExchangeRatesDto, GetAccountBalancesDto, GetAdvanceRoutesLiFiDto, GetSupportedAssetsDto, GetTransactionStatusDto, GetExchangeOffersDto, GetExchangeSupportedAssetsDto, GetNftListDto, GetStepTransactionsLiFiDto, GetTokenListDto, GetTokenListsDto, GetTransactionDto, GetTransactionsDto, GetQuotesDto, validateDto } from "./dto"; import { BigNumber } from "ethers"; export class DataUtils { @@ -224,4 +224,57 @@ export class DataUtils { return data; } -} \ No newline at end of file + + /** + * gets supported tokens + * @param dto + * @return Promise + */ + async getSupportedAssets(dto: GetSupportedAssetsDto): Promise { + const { chainId, provider } = await validateDto(dto, GetSupportedAssetsDto); + + return this.dataModule.getSupportedAssets(chainId, provider); + } + + /** + * gets quote transactions + * @param dto + * @return Promise + */ + async getQuotes(dto: GetQuotesDto): Promise { + const { + fromAddress, + toAddress, + fromChainId, + toChainId, + fromToken, + fromAmount, + slippage, + provider + } = await validateDto(dto, GetQuotesDto, { + addressKeys: ['fromAddress', 'toAddress', 'fromToken'], + }); + + return this.dataModule.getQuotes( + fromAddress, + toAddress, + fromChainId, + toChainId, + fromToken, + BigNumber.from(fromAmount), + slippage, + provider + ); + } + + /** + * gets transaction status + * @param dto + * @return Promise + */ + async getTransactionStatus(dto: GetTransactionStatusDto): Promise { + const { fromChainId, toChainId, transactionHash, provider } = await validateDto(dto, GetTransactionStatusDto); + + return this.dataModule.getTransactionStatus(fromChainId, toChainId, transactionHash, provider); + } +} diff --git a/src/sdk/dto/get-quotes.dto.ts b/src/sdk/dto/get-quotes.dto.ts new file mode 100644 index 00000000..d33529a4 --- /dev/null +++ b/src/sdk/dto/get-quotes.dto.ts @@ -0,0 +1,29 @@ +import { BigNumberish } from 'ethers'; +import { IsAddress, IsBigNumberish } from './validators'; +import { IsOptional } from 'class-validator'; +import { BridgingProvider } from '../data'; + +export class GetQuotesDto { + @IsAddress() + fromAddress: string; + + @IsAddress() + toAddress: string; + + fromChainId: number; + + toChainId: number; + + @IsAddress() + fromToken: string; + + @IsBigNumberish({ + positive: true, + }) + fromAmount: BigNumberish; + + slippage: number; + + @IsOptional() + provider?: BridgingProvider; +} diff --git a/src/sdk/dto/get-supported-assets.dto.ts b/src/sdk/dto/get-supported-assets.dto.ts new file mode 100644 index 00000000..aca3fa31 --- /dev/null +++ b/src/sdk/dto/get-supported-assets.dto.ts @@ -0,0 +1,12 @@ +import { IsInt, IsOptional, IsPositive } from 'class-validator'; +import { BridgingProvider } from '../data'; + +export class GetSupportedAssetsDto { + @IsOptional() + @IsPositive() + @IsInt() + chainId?: number = null; + + @IsOptional() + provider?: BridgingProvider; +} diff --git a/src/sdk/dto/get-transaction-status.dto.ts b/src/sdk/dto/get-transaction-status.dto.ts new file mode 100644 index 00000000..2b4d8983 --- /dev/null +++ b/src/sdk/dto/get-transaction-status.dto.ts @@ -0,0 +1,19 @@ +import { IsInt, IsOptional, IsPositive } from 'class-validator'; +import { IsHex32 } from './validators'; +import { BridgingProvider } from '../data'; + +export class GetTransactionStatusDto { + @IsPositive() + @IsInt() + fromChainId: number; + + @IsPositive() + @IsInt() + toChainId: number; + + @IsHex32() + transactionHash: string; + + @IsOptional() + provider?: BridgingProvider; +} diff --git a/src/sdk/dto/index.ts b/src/sdk/dto/index.ts index 8de73be2..c533fd1c 100644 --- a/src/sdk/dto/index.ts +++ b/src/sdk/dto/index.ts @@ -14,3 +14,6 @@ export * from './pagination.dto'; export * from './get-exchange-supported-assets.dto'; export * from './get-token-lists.dto'; export * from './get-transactions.dto'; +export * from './get-supported-assets.dto'; +export * from './get-quotes.dto'; +export * from './get-transaction-status.dto';